@navikt/ds-react 0.17.16 → 0.17.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cjs/index.js CHANGED
@@ -37,6 +37,7 @@ __exportStar(require("./tag"), exports);
37
37
  __exportStar(require("./toggle-group"), exports);
38
38
  __exportStar(require("./table"), exports);
39
39
  __exportStar(require("./tabs"), exports);
40
+ __exportStar(require("./tooltip"), exports);
40
41
  __exportStar(require("./typography"), exports);
41
42
  __exportStar(require("./util"), exports);
42
43
  /* Navno spesific packages */
@@ -50,7 +50,7 @@ const ReadMore = (0, react_1.forwardRef)((_a, ref) => {
50
50
  : react_collapse_1.UnmountClosed;
51
51
  const isOpened = open !== null && open !== void 0 ? open : internalOpen;
52
52
  return (react_1.default.createElement(react_1.default.Fragment, null,
53
- react_1.default.createElement("button", Object.assign({}, rest, { className: (0, classnames_1.default)("navds-read-more", "navds-body-short", "navds-body-short--small", className, {
53
+ react_1.default.createElement("button", Object.assign({ type: "button" }, rest, { className: (0, classnames_1.default)("navds-read-more", "navds-body-short", "navds-body-short--small", className, {
54
54
  "navds-read-more--open": isOpened,
55
55
  }), onClick: (e) => {
56
56
  if (open === undefined) {
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __rest = (this && this.__rest) || function (s, e) {
26
+ var t = {};
27
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
28
+ t[p] = s[p];
29
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
30
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
31
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
32
+ t[p[i]] = s[p[i]];
33
+ }
34
+ return t;
35
+ };
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const classnames_1 = __importDefault(require("classnames"));
41
+ const react_1 = __importStar(require("react"));
42
+ const __1 = require("..");
43
+ const react_dom_1 = require("@floating-ui/react-dom");
44
+ const react_merge_refs_1 = __importDefault(require("react-merge-refs"));
45
+ const portal_1 = __importDefault(require("./portal"));
46
+ const util_1 = require("../util");
47
+ const Tooltip = (0, react_1.forwardRef)((_a, ref) => {
48
+ var { children, className, arrow: _arrow = true, placement: _placement = "top", open, defaultOpen = false, offset: _offset, content, delay = 150, id, keys, maxChar = 80 } = _a, rest = __rest(_a, ["children", "className", "arrow", "placement", "open", "defaultOpen", "offset", "content", "delay", "id", "keys", "maxChar"]);
49
+ const arrowRef = (0, react_1.useRef)(null);
50
+ const [isOpen, setIsOpen] = (0, react_1.useState)(defaultOpen);
51
+ const openTimerRef = (0, react_1.useRef)(0);
52
+ const leaveTimerRef = (0, react_1.useRef)(0);
53
+ const isMouseDownRef = (0, react_1.useRef)(false);
54
+ const ariaId = (0, util_1.useId)(id);
55
+ const { x, y, update, placement, refs, middlewareData: { arrow: { x: arrowX, y: arrowY } = {}, hide: { referenceHidden } = {}, }, } = (0, react_dom_1.useFloating)({
56
+ placement: _placement,
57
+ middleware: [
58
+ (0, react_dom_1.shift)(),
59
+ (0, react_dom_1.flip)({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
60
+ (0, react_dom_1.arrow)({ element: arrowRef, padding: 5 }),
61
+ (0, react_dom_1.hide)(),
62
+ ],
63
+ });
64
+ /* https://floating-ui.com/docs/react-dom#updating */
65
+ (0, react_1.useEffect)(() => {
66
+ if (!refs.reference.current || !refs.floating.current) {
67
+ return;
68
+ }
69
+ // Only call this when the floating element is rendered
70
+ return (0, react_dom_1.autoUpdate)(refs.reference.current, refs.floating.current, update);
71
+ }, [refs.reference, refs.floating, update, open, isOpen]);
72
+ const handleOpen = (0, react_1.useCallback)(() => {
73
+ window.clearTimeout(openTimerRef.current);
74
+ window.clearTimeout(leaveTimerRef.current);
75
+ setIsOpen(true);
76
+ }, [setIsOpen]);
77
+ const handleDelayedOpen = (0, react_1.useCallback)(() => {
78
+ window.clearTimeout(openTimerRef.current);
79
+ window.clearTimeout(leaveTimerRef.current);
80
+ openTimerRef.current = window.setTimeout(() => {
81
+ setIsOpen(true);
82
+ }, delay);
83
+ }, [delay, setIsOpen]);
84
+ const handleClose = (0, react_1.useCallback)(() => {
85
+ window.clearTimeout(openTimerRef.current);
86
+ leaveTimerRef.current = window.setTimeout(() => {
87
+ setIsOpen(false);
88
+ }, 50);
89
+ }, [setIsOpen]);
90
+ const handleMouseUp = (0, react_1.useCallback)(() => (isMouseDownRef.current = false), []);
91
+ (0, react_1.useEffect)(() => {
92
+ // eslint-disable-next-line react-hooks/exhaustive-deps
93
+ return () => window.clearTimeout(openTimerRef.current);
94
+ }, []);
95
+ (0, react_1.useEffect)(() => {
96
+ return () => document.removeEventListener("mouseup", handleMouseUp);
97
+ }, [handleMouseUp]);
98
+ (0, __1.useEventListener)("keydown", (0, react_1.useCallback)((e) => e.key === "Escape" && handleClose(), [handleClose]), document);
99
+ /* https://floating-ui.com/docs/react-dom#stable-ref-prop */
100
+ const stableRef = (0, react_1.useMemo)(() => (0, react_merge_refs_1.default)([ref, refs.floating]), [
101
+ ref,
102
+ refs.floating,
103
+ ]);
104
+ if (!children ||
105
+ (children === null || children === void 0 ? void 0 : children.type) === react_1.default.Fragment ||
106
+ children === react_1.default.Fragment) {
107
+ console.error("<Tooltip> children needs to be a single ReactElement and not <React.Fragment/>/<></>");
108
+ return null;
109
+ }
110
+ if ((content === null || content === void 0 ? void 0 : content.length) > maxChar) {
111
+ console.error(`Because of strict accessibility concers we encourage all Tooltips to have less than 80 characters. Can be overwritten with the maxChar-prop`);
112
+ return null;
113
+ }
114
+ return (react_1.default.createElement(react_1.default.Fragment, null,
115
+ (0, react_1.cloneElement)(children, Object.assign(Object.assign({}, children.props), { "aria-describedby": open || isOpen
116
+ ? (0, classnames_1.default)(ariaId, children === null || children === void 0 ? void 0 : children.props["aria-describedby"])
117
+ : children === null || children === void 0 ? void 0 : children.props["aria-describedby"], ref: (0, react_merge_refs_1.default)([children.ref, refs.reference]), onMouseEnter: (0, __1.composeEventHandlers)(children.props.onMouseEnter, handleDelayedOpen), onMouseLeave: (0, __1.composeEventHandlers)(children.props.onMouseLeave, handleClose), onMouseDown: (0, __1.composeEventHandlers)(children.props.onMouseDown, () => {
118
+ isMouseDownRef.current = true;
119
+ document.addEventListener("mouseup", handleMouseUp, { once: true });
120
+ }), onFocus: (0, __1.composeEventHandlers)(children.props.onFocus, () => !isMouseDownRef.current && handleOpen()), onBlur: (0, __1.composeEventHandlers)(children.props.onBlur, handleClose) })),
121
+ (open !== null && open !== void 0 ? open : isOpen) && (react_1.default.createElement(portal_1.default, null,
122
+ react_1.default.createElement("div", Object.assign({ ref: stableRef }, rest, { onMouseEnter: handleOpen, onMouseLeave: handleClose, role: "tooltip", id: ariaId, style: {
123
+ position: "absolute",
124
+ top: y !== null && y !== void 0 ? y : "",
125
+ left: x !== null && x !== void 0 ? x : "",
126
+ visibility: referenceHidden ? "hidden" : "visible",
127
+ }, "data-side": placement, className: (0, classnames_1.default)("navds-tooltip", "navds-detail navds-detail--small", className) }),
128
+ react_1.default.createElement("div", { className: "navds-tooltip__inner", style: {
129
+ [{
130
+ top: "marginBottom",
131
+ right: "marginLeft",
132
+ bottom: "marginTop",
133
+ left: "marginRight",
134
+ }[placement]]: _offset ? _offset : _arrow ? 10 : 2,
135
+ } },
136
+ content,
137
+ keys && (react_1.default.createElement("span", { className: "navds-tooltip__keys" }, keys.map((key) => (react_1.default.createElement(__1.Detail, { size: "small", as: "kbd", key: key, className: "navds-tooltip__key" }, key))))),
138
+ _arrow && (react_1.default.createElement("div", { ref: (node) => {
139
+ arrowRef.current = node;
140
+ }, className: "navds-tooltip__arrow", style: {
141
+ left: arrowX != null ? `${arrowX}px` : "",
142
+ top: arrowY != null ? `${arrowY}px` : "",
143
+ right: "",
144
+ bottom: "",
145
+ [{
146
+ top: "bottom",
147
+ right: "left",
148
+ bottom: "top",
149
+ left: "right",
150
+ }[placement]]: "-3.5px",
151
+ } }))))))));
152
+ });
153
+ exports.default = Tooltip;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.Tooltip = void 0;
21
+ var Tooltip_1 = require("./Tooltip");
22
+ Object.defineProperty(exports, "Tooltip", { enumerable: true, get: function () { return __importDefault(Tooltip_1).default; } });
23
+ __exportStar(require("./Tooltip"), exports);
@@ -0,0 +1,6 @@
1
+ {
2
+ "sideEffects": false,
3
+ "main": "./index.js",
4
+ "module": "../../esm/tooltip/index.js",
5
+ "types": "../../esm/tooltip/index.d.ts"
6
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* https://github.com/radix-ui/primitives/blob/main/packages/react/portal/src/Portal.tsx */
7
+ const react_dom_1 = __importDefault(require("react-dom"));
8
+ const Portal = ({ children }) => {
9
+ var _a;
10
+ const hostElement = (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) === null || _a === void 0 ? void 0 : _a.body;
11
+ if (hostElement) {
12
+ return react_dom_1.default.createPortal(children, hostElement);
13
+ }
14
+ // bail out of ssr
15
+ return null;
16
+ };
17
+ exports.default = Portal;
package/cjs/util/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.useEventListener = exports.omit = void 0;
17
+ exports.composeEventHandlers = exports.useEventListener = exports.omit = void 0;
18
18
  const react_1 = require("react");
19
19
  __exportStar(require("./OverridableComponent"), exports);
20
20
  __exportStar(require("./useId"), exports);
@@ -35,3 +35,13 @@ const useEventListener = (name, handler, target = window) => {
35
35
  }, [name, handler, target]);
36
36
  };
37
37
  exports.useEventListener = useEventListener;
38
+ /* https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx */
39
+ const composeEventHandlers = (originalEventHandler, ourEventHandler) => {
40
+ return function handleEvent(event) {
41
+ originalEventHandler === null || originalEventHandler === void 0 ? void 0 : originalEventHandler(event);
42
+ if (!event.defaultPrevented) {
43
+ return ourEventHandler === null || ourEventHandler === void 0 ? void 0 : ourEventHandler(event);
44
+ }
45
+ };
46
+ };
47
+ exports.composeEventHandlers = composeEventHandlers;
package/esm/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export * from "./tag";
21
21
  export * from "./toggle-group";
22
22
  export * from "./table";
23
23
  export * from "./tabs";
24
+ export * from "./tooltip";
24
25
  export * from "./typography";
25
26
  export * from "./util";
26
27
  export * from "./card";
package/esm/index.js CHANGED
@@ -21,6 +21,7 @@ export * from "./tag";
21
21
  export * from "./toggle-group";
22
22
  export * from "./table";
23
23
  export * from "./tabs";
24
+ export * from "./tooltip";
24
25
  export * from "./typography";
25
26
  export * from "./util";
26
27
  /* Navno spesific packages */
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AAEvB,6BAA6B;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AAEvB,6BAA6B;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC"}
@@ -22,7 +22,7 @@ const ReadMore = forwardRef((_a, ref) => {
22
22
  : UnmountClosed;
23
23
  const isOpened = open !== null && open !== void 0 ? open : internalOpen;
24
24
  return (React.createElement(React.Fragment, null,
25
- React.createElement("button", Object.assign({}, rest, { className: cl("navds-read-more", "navds-body-short", "navds-body-short--small", className, {
25
+ React.createElement("button", Object.assign({ type: "button" }, rest, { className: cl("navds-read-more", "navds-body-short", "navds-body-short--small", className, {
26
26
  "navds-read-more--open": isOpened,
27
27
  }), onClick: (e) => {
28
28
  if (open === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"ReadMore.js","sourceRoot":"","sources":["../../src/read-more/ReadMore.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AA6BzC,MAAM,QAAQ,GAAG,UAAU,CACzB,CACE,EASC,EACD,GAAG,EACH,EAAE;QAXF,EACE,SAAS,EACT,MAAM,EACN,uBAAuB,GAAG,KAAK,EAC/B,QAAQ,EACR,IAAI,EACJ,WAAW,GAAG,KAAK,EACnB,OAAO,OAER,EADI,IAAI,cART,gGASC,CADQ;IAIT,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAU,WAAW,CAAC,CAAC;IACvE,MAAM,iBAAiB,GAAG,uBAAuB;QAC/C,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,aAAa,CAAC;IAElB,MAAM,QAAQ,GAAG,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,YAAY,CAAC;IAEtC,OAAO,CACL;QACE,gDACM,IAAI,IACR,SAAS,EAAE,EAAE,CACX,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,SAAS,EACT;gBACE,uBAAuB,EAAE,QAAQ;aAClC,CACF,EACD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBACb,IAAI,IAAI,KAAK,SAAS,EAAE;oBACtB,eAAe,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;iBACtC;gBACD,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,CAAC;YACf,CAAC,mBACc,QAAQ,EACvB,GAAG,EAAE,GAAG;YAER,oBAAC,MAAM,IAAC,SAAS,EAAC,8BAA8B,wBAAe;YAC/D,kCAAO,MAAM,CAAQ,CACd;QACT,oBAAC,iBAAiB,IAAC,QAAQ,EAAE,QAAQ;YACnC,6BAAK,SAAS,EAAC,0BAA0B;gBACvC,oBAAC,QAAQ,IAAC,IAAI,EAAC,OAAO,IAAE,QAAQ,CAAY,CACxC,CACY,CACnB,CACJ,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"ReadMore.js","sourceRoot":"","sources":["../../src/read-more/ReadMore.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AA6BzC,MAAM,QAAQ,GAAG,UAAU,CACzB,CACE,EASC,EACD,GAAG,EACH,EAAE;QAXF,EACE,SAAS,EACT,MAAM,EACN,uBAAuB,GAAG,KAAK,EAC/B,QAAQ,EACR,IAAI,EACJ,WAAW,GAAG,KAAK,EACnB,OAAO,OAER,EADI,IAAI,cART,gGASC,CADQ;IAIT,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAU,WAAW,CAAC,CAAC;IACvE,MAAM,iBAAiB,GAAG,uBAAuB;QAC/C,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,aAAa,CAAC;IAElB,MAAM,QAAQ,GAAG,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,YAAY,CAAC;IAEtC,OAAO,CACL;QACE,8CACE,IAAI,EAAC,QAAQ,IACT,IAAI,IACR,SAAS,EAAE,EAAE,CACX,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,SAAS,EACT;gBACE,uBAAuB,EAAE,QAAQ;aAClC,CACF,EACD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBACb,IAAI,IAAI,KAAK,SAAS,EAAE;oBACtB,eAAe,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;iBACtC;gBACD,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAG,CAAC,CAAC,CAAC;YACf,CAAC,mBACc,QAAQ,EACvB,GAAG,EAAE,GAAG;YAER,oBAAC,MAAM,IAAC,SAAS,EAAC,8BAA8B,wBAAe;YAC/D,kCAAO,MAAM,CAAQ,CACd;QACT,oBAAC,iBAAiB,IAAC,QAAQ,EAAE,QAAQ;YACnC,6BAAK,SAAS,EAAC,0BAA0B;gBACvC,oBAAC,QAAQ,IAAC,IAAI,EAAC,OAAO,IAAE,QAAQ,CAAY,CACxC,CACY,CACnB,CACJ,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,51 @@
1
+ import React, { HTMLAttributes } from "react";
2
+ export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
3
+ /**
4
+ * Element tooltip anchors to
5
+ */
6
+ children: React.ReactElement & React.RefAttributes<HTMLElement>;
7
+ /**
8
+ * Open state for contolled tooltip
9
+ */
10
+ open?: boolean;
11
+ /**
12
+ * Tells tooltip to start in open state
13
+ * @note "open"-prop overwrites this
14
+ */
15
+ defaultOpen?: boolean;
16
+ /**
17
+ * Orientation for tooltip
18
+ * @default "top"
19
+ */
20
+ placement?: "top" | "right" | "bottom" | "left";
21
+ /**
22
+ * Toggles rendering of arrow
23
+ * @default true
24
+ */
25
+ arrow?: boolean;
26
+ /**
27
+ * Distance from anchor to tooltip
28
+ * @default 10px with arrow, 2px without arrow
29
+ */
30
+ offset?: number;
31
+ /**
32
+ * Content shown in tooltip
33
+ */
34
+ content: string;
35
+ /**
36
+ * Sets max allowed character length
37
+ * @default 80
38
+ */
39
+ maxChar?: number;
40
+ /**
41
+ * Adds a delay in milliseconds before opening tooltip
42
+ * @default 300
43
+ */
44
+ delay?: number;
45
+ /**
46
+ * List of Keyboard-keys for shortcuts
47
+ */
48
+ keys?: string[];
49
+ }
50
+ declare const Tooltip: React.ForwardRefExoticComponent<TooltipProps & React.RefAttributes<HTMLDivElement>>;
51
+ export default Tooltip;
@@ -0,0 +1,126 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import cl from "classnames";
13
+ import React, { cloneElement, forwardRef, useCallback, useEffect, useMemo, useRef, useState, } from "react";
14
+ import { composeEventHandlers, Detail, useEventListener } from "..";
15
+ import { useFloating, arrow as flArrow, shift, autoUpdate, flip, hide, } from "@floating-ui/react-dom";
16
+ import mergeRefs from "react-merge-refs";
17
+ import Portal from "./portal";
18
+ import { useId } from "../util";
19
+ const Tooltip = forwardRef((_a, ref) => {
20
+ var { children, className, arrow: _arrow = true, placement: _placement = "top", open, defaultOpen = false, offset: _offset, content, delay = 150, id, keys, maxChar = 80 } = _a, rest = __rest(_a, ["children", "className", "arrow", "placement", "open", "defaultOpen", "offset", "content", "delay", "id", "keys", "maxChar"]);
21
+ const arrowRef = useRef(null);
22
+ const [isOpen, setIsOpen] = useState(defaultOpen);
23
+ const openTimerRef = useRef(0);
24
+ const leaveTimerRef = useRef(0);
25
+ const isMouseDownRef = useRef(false);
26
+ const ariaId = useId(id);
27
+ const { x, y, update, placement, refs, middlewareData: { arrow: { x: arrowX, y: arrowY } = {}, hide: { referenceHidden } = {}, }, } = useFloating({
28
+ placement: _placement,
29
+ middleware: [
30
+ shift(),
31
+ flip({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
32
+ flArrow({ element: arrowRef, padding: 5 }),
33
+ hide(),
34
+ ],
35
+ });
36
+ /* https://floating-ui.com/docs/react-dom#updating */
37
+ useEffect(() => {
38
+ if (!refs.reference.current || !refs.floating.current) {
39
+ return;
40
+ }
41
+ // Only call this when the floating element is rendered
42
+ return autoUpdate(refs.reference.current, refs.floating.current, update);
43
+ }, [refs.reference, refs.floating, update, open, isOpen]);
44
+ const handleOpen = useCallback(() => {
45
+ window.clearTimeout(openTimerRef.current);
46
+ window.clearTimeout(leaveTimerRef.current);
47
+ setIsOpen(true);
48
+ }, [setIsOpen]);
49
+ const handleDelayedOpen = useCallback(() => {
50
+ window.clearTimeout(openTimerRef.current);
51
+ window.clearTimeout(leaveTimerRef.current);
52
+ openTimerRef.current = window.setTimeout(() => {
53
+ setIsOpen(true);
54
+ }, delay);
55
+ }, [delay, setIsOpen]);
56
+ const handleClose = useCallback(() => {
57
+ window.clearTimeout(openTimerRef.current);
58
+ leaveTimerRef.current = window.setTimeout(() => {
59
+ setIsOpen(false);
60
+ }, 50);
61
+ }, [setIsOpen]);
62
+ const handleMouseUp = useCallback(() => (isMouseDownRef.current = false), []);
63
+ useEffect(() => {
64
+ // eslint-disable-next-line react-hooks/exhaustive-deps
65
+ return () => window.clearTimeout(openTimerRef.current);
66
+ }, []);
67
+ useEffect(() => {
68
+ return () => document.removeEventListener("mouseup", handleMouseUp);
69
+ }, [handleMouseUp]);
70
+ useEventListener("keydown", useCallback((e) => e.key === "Escape" && handleClose(), [handleClose]), document);
71
+ /* https://floating-ui.com/docs/react-dom#stable-ref-prop */
72
+ const stableRef = useMemo(() => mergeRefs([ref, refs.floating]), [
73
+ ref,
74
+ refs.floating,
75
+ ]);
76
+ if (!children ||
77
+ (children === null || children === void 0 ? void 0 : children.type) === React.Fragment ||
78
+ children === React.Fragment) {
79
+ console.error("<Tooltip> children needs to be a single ReactElement and not <React.Fragment/>/<></>");
80
+ return null;
81
+ }
82
+ if ((content === null || content === void 0 ? void 0 : content.length) > maxChar) {
83
+ console.error(`Because of strict accessibility concers we encourage all Tooltips to have less than 80 characters. Can be overwritten with the maxChar-prop`);
84
+ return null;
85
+ }
86
+ return (React.createElement(React.Fragment, null,
87
+ cloneElement(children, Object.assign(Object.assign({}, children.props), { "aria-describedby": open || isOpen
88
+ ? cl(ariaId, children === null || children === void 0 ? void 0 : children.props["aria-describedby"])
89
+ : children === null || children === void 0 ? void 0 : children.props["aria-describedby"], ref: mergeRefs([children.ref, refs.reference]), onMouseEnter: composeEventHandlers(children.props.onMouseEnter, handleDelayedOpen), onMouseLeave: composeEventHandlers(children.props.onMouseLeave, handleClose), onMouseDown: composeEventHandlers(children.props.onMouseDown, () => {
90
+ isMouseDownRef.current = true;
91
+ document.addEventListener("mouseup", handleMouseUp, { once: true });
92
+ }), onFocus: composeEventHandlers(children.props.onFocus, () => !isMouseDownRef.current && handleOpen()), onBlur: composeEventHandlers(children.props.onBlur, handleClose) })),
93
+ (open !== null && open !== void 0 ? open : isOpen) && (React.createElement(Portal, null,
94
+ React.createElement("div", Object.assign({ ref: stableRef }, rest, { onMouseEnter: handleOpen, onMouseLeave: handleClose, role: "tooltip", id: ariaId, style: {
95
+ position: "absolute",
96
+ top: y !== null && y !== void 0 ? y : "",
97
+ left: x !== null && x !== void 0 ? x : "",
98
+ visibility: referenceHidden ? "hidden" : "visible",
99
+ }, "data-side": placement, className: cl("navds-tooltip", "navds-detail navds-detail--small", className) }),
100
+ React.createElement("div", { className: "navds-tooltip__inner", style: {
101
+ [{
102
+ top: "marginBottom",
103
+ right: "marginLeft",
104
+ bottom: "marginTop",
105
+ left: "marginRight",
106
+ }[placement]]: _offset ? _offset : _arrow ? 10 : 2,
107
+ } },
108
+ content,
109
+ keys && (React.createElement("span", { className: "navds-tooltip__keys" }, keys.map((key) => (React.createElement(Detail, { size: "small", as: "kbd", key: key, className: "navds-tooltip__key" }, key))))),
110
+ _arrow && (React.createElement("div", { ref: (node) => {
111
+ arrowRef.current = node;
112
+ }, className: "navds-tooltip__arrow", style: {
113
+ left: arrowX != null ? `${arrowX}px` : "",
114
+ top: arrowY != null ? `${arrowY}px` : "",
115
+ right: "",
116
+ bottom: "",
117
+ [{
118
+ top: "bottom",
119
+ right: "left",
120
+ bottom: "top",
121
+ left: "right",
122
+ }[placement]]: "-3.5px",
123
+ } }))))))));
124
+ });
125
+ export default Tooltip;
126
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../src/tooltip/Tooltip.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { default as Tooltip } from "./Tooltip";
2
+ export * from "./Tooltip";
@@ -0,0 +1,3 @@
1
+ export { default as Tooltip } from "./Tooltip";
2
+ export * from "./Tooltip";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tooltip/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC;AAC/C,cAAc,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ declare const Portal: ({ children }: {
3
+ children: any;
4
+ }) => import("react").ReactPortal | null;
5
+ export default Portal;
@@ -0,0 +1,13 @@
1
+ /* https://github.com/radix-ui/primitives/blob/main/packages/react/portal/src/Portal.tsx */
2
+ import ReactDOM from "react-dom";
3
+ const Portal = ({ children }) => {
4
+ var _a;
5
+ const hostElement = (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) === null || _a === void 0 ? void 0 : _a.body;
6
+ if (hostElement) {
7
+ return ReactDOM.createPortal(children, hostElement);
8
+ }
9
+ // bail out of ssr
10
+ return null;
11
+ };
12
+ export default Portal;
13
+ //# sourceMappingURL=portal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal.js","sourceRoot":"","sources":["../../src/tooltip/portal.tsx"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,OAAO,QAAQ,MAAM,WAAW,CAAC;AAEjC,MAAM,MAAM,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;;IAC9B,MAAM,WAAW,GAAG,MAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,QAAQ,0CAAE,IAAI,CAAC;IAE/C,IAAI,WAAW,EAAE;QACf,OAAO,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;KACrD;IAED,kBAAkB;IAClB,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -6,3 +6,4 @@ export interface ListenerT {
6
6
  removeEventListener(name: string, handler: (event?: any) => void, ...args: any[]): any;
7
7
  }
8
8
  export declare const useEventListener: <T extends ListenerT>(name: Parameters<ListenerT["addEventListener"]>[0], handler: Parameters<ListenerT["addEventListener"]>[1], target?: Window | T | null) => void;
9
+ export declare const composeEventHandlers: <E>(originalEventHandler?: ((event: E) => void) | undefined, ourEventHandler?: ((event: E) => void) | undefined) => (event: E) => void;
package/esm/util/index.js CHANGED
@@ -16,4 +16,13 @@ export const useEventListener = (name, handler, target = window) => {
16
16
  };
17
17
  }, [name, handler, target]);
18
18
  };
19
+ /* https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx */
20
+ export const composeEventHandlers = (originalEventHandler, ourEventHandler) => {
21
+ return function handleEvent(event) {
22
+ originalEventHandler === null || originalEventHandler === void 0 ? void 0 : originalEventHandler(event);
23
+ if (!event.defaultPrevented) {
24
+ return ourEventHandler === null || ourEventHandler === void 0 ? void 0 : ourEventHandler(event);
25
+ }
26
+ };
27
+ };
19
28
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC;AAExB,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,KAAe,EAAE,EAAE,CACnD,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;KAChB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;KACvC,MAAM,CACL,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,iCAClB,GAAG,KACN,CAAC,GAAG,CAAC,EAAE,KAAK,IACZ,EACF,EAAE,CACH,CAAC;AAgBN,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAAkD,EAClD,OAAqD,EACrD,SAA4B,MAAM,EAC5B,EAAE;IACR,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,EAAE;YACX,OAAO;SACR;QACD,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,GAAG,EAAE;YACV,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9B,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC;AAExB,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,KAAe,EAAE,EAAE,CACnD,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;KAChB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;KACvC,MAAM,CACL,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,iCAClB,GAAG,KACN,CAAC,GAAG,CAAC,EAAE,KAAK,IACZ,EACF,EAAE,CACH,CAAC;AAgBN,wEAAwE;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAAkD,EAClD,OAAqD,EACrD,SAA4B,MAAM,EAC5B,EAAE;IACR,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,EAAE;YACX,OAAO;SACR;QACD,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,GAAG,EAAE;YACV,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,oBAAyC,EACzC,eAAoC,EACpC,EAAE;IACF,OAAO,SAAS,WAAW,CAAC,KAAQ;QAClC,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAG,KAAK,CAAC,CAAC;QAE9B,IAAI,CAAG,KAA2B,CAAC,gBAAgB,EAAE;YACnD,OAAO,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAG,KAAK,CAAC,CAAC;SACjC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navikt/ds-react",
3
- "version": "0.17.16",
3
+ "version": "0.17.17",
4
4
  "private": false,
5
5
  "description": "NAV designsystem react components",
6
6
  "author": "NAV Designsystem team",
@@ -34,6 +34,7 @@
34
34
  "test": "jest"
35
35
  },
36
36
  "dependencies": {
37
+ "@floating-ui/react-dom": "0.6.0",
37
38
  "@material-ui/core": "^4.12.3",
38
39
  "@navikt/ds-icons": "^0.8.6",
39
40
  "@popperjs/core": "^2.10.1",
@@ -68,5 +69,5 @@
68
69
  "@types/react": "^17.0.30",
69
70
  "react": "^17.0.0"
70
71
  },
71
- "gitHead": "61f6b62c9e20e095d220631b5c9fa1d7a7cada38"
72
+ "gitHead": "fcbd614a3444afa7fd07c0c133cc754206e5f106"
72
73
  }
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export * from "./tag";
21
21
  export * from "./toggle-group";
22
22
  export * from "./table";
23
23
  export * from "./tabs";
24
+ export * from "./tooltip";
24
25
  export * from "./typography";
25
26
  export * from "./util";
26
27
 
@@ -55,6 +55,7 @@ const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
55
55
  return (
56
56
  <>
57
57
  <button
58
+ type="button"
58
59
  {...rest}
59
60
  className={cl(
60
61
  "navds-read-more",
@@ -0,0 +1,301 @@
1
+ import cl from "classnames";
2
+ import React, {
3
+ cloneElement,
4
+ forwardRef,
5
+ HTMLAttributes,
6
+ useCallback,
7
+ useEffect,
8
+ useMemo,
9
+ useRef,
10
+ useState,
11
+ } from "react";
12
+ import { composeEventHandlers, Detail, useEventListener } from "..";
13
+ import {
14
+ useFloating,
15
+ arrow as flArrow,
16
+ shift,
17
+ autoUpdate,
18
+ flip,
19
+ hide,
20
+ } from "@floating-ui/react-dom";
21
+ import mergeRefs from "react-merge-refs";
22
+ import Portal from "./portal";
23
+ import { useId } from "../util";
24
+
25
+ export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
26
+ /**
27
+ * Element tooltip anchors to
28
+ */
29
+ children: React.ReactElement & React.RefAttributes<HTMLElement>;
30
+ /**
31
+ * Open state for contolled tooltip
32
+ */
33
+ open?: boolean;
34
+ /**
35
+ * Tells tooltip to start in open state
36
+ * @note "open"-prop overwrites this
37
+ */
38
+ defaultOpen?: boolean;
39
+ /**
40
+ * Orientation for tooltip
41
+ * @default "top"
42
+ */
43
+ placement?: "top" | "right" | "bottom" | "left";
44
+ /**
45
+ * Toggles rendering of arrow
46
+ * @default true
47
+ */
48
+ arrow?: boolean;
49
+ /**
50
+ * Distance from anchor to tooltip
51
+ * @default 10px with arrow, 2px without arrow
52
+ */
53
+ offset?: number;
54
+ /**
55
+ * Content shown in tooltip
56
+ */
57
+ content: string;
58
+ /**
59
+ * Sets max allowed character length
60
+ * @default 80
61
+ */
62
+ maxChar?: number;
63
+ /**
64
+ * Adds a delay in milliseconds before opening tooltip
65
+ * @default 300
66
+ */
67
+ delay?: number;
68
+ /**
69
+ * List of Keyboard-keys for shortcuts
70
+ */
71
+ keys?: string[];
72
+ }
73
+
74
+ const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
75
+ (
76
+ {
77
+ children,
78
+ className,
79
+ arrow: _arrow = true,
80
+ placement: _placement = "top",
81
+ open,
82
+ defaultOpen = false,
83
+ offset: _offset,
84
+ content,
85
+ delay = 150,
86
+ id,
87
+ keys,
88
+ maxChar = 80,
89
+ ...rest
90
+ },
91
+ ref
92
+ ) => {
93
+ const arrowRef = useRef<HTMLDivElement | null>(null);
94
+ const [isOpen, setIsOpen] = useState(defaultOpen);
95
+ const openTimerRef = useRef(0);
96
+ const leaveTimerRef = useRef(0);
97
+ const isMouseDownRef = useRef(false);
98
+
99
+ const ariaId = useId(id);
100
+
101
+ const {
102
+ x,
103
+ y,
104
+ update,
105
+ placement,
106
+ refs,
107
+ middlewareData: {
108
+ arrow: { x: arrowX, y: arrowY } = {},
109
+ hide: { referenceHidden } = {},
110
+ },
111
+ } = useFloating({
112
+ placement: _placement,
113
+ middleware: [
114
+ shift(),
115
+ flip({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
116
+ flArrow({ element: arrowRef, padding: 5 }),
117
+ hide(),
118
+ ],
119
+ });
120
+
121
+ /* https://floating-ui.com/docs/react-dom#updating */
122
+ useEffect(() => {
123
+ if (!refs.reference.current || !refs.floating.current) {
124
+ return;
125
+ }
126
+
127
+ // Only call this when the floating element is rendered
128
+ return autoUpdate(refs.reference.current, refs.floating.current, update);
129
+ }, [refs.reference, refs.floating, update, open, isOpen]);
130
+
131
+ const handleOpen = useCallback(() => {
132
+ window.clearTimeout(openTimerRef.current);
133
+ window.clearTimeout(leaveTimerRef.current);
134
+ setIsOpen(true);
135
+ }, [setIsOpen]);
136
+
137
+ const handleDelayedOpen = useCallback(() => {
138
+ window.clearTimeout(openTimerRef.current);
139
+ window.clearTimeout(leaveTimerRef.current);
140
+ openTimerRef.current = window.setTimeout(() => {
141
+ setIsOpen(true);
142
+ }, delay);
143
+ }, [delay, setIsOpen]);
144
+
145
+ const handleClose = useCallback(() => {
146
+ window.clearTimeout(openTimerRef.current);
147
+ leaveTimerRef.current = window.setTimeout(() => {
148
+ setIsOpen(false);
149
+ }, 50);
150
+ }, [setIsOpen]);
151
+
152
+ const handleMouseUp = useCallback(
153
+ () => (isMouseDownRef.current = false),
154
+ []
155
+ );
156
+
157
+ useEffect(() => {
158
+ // eslint-disable-next-line react-hooks/exhaustive-deps
159
+ return () => window.clearTimeout(openTimerRef.current);
160
+ }, []);
161
+
162
+ useEffect(() => {
163
+ return () => document.removeEventListener("mouseup", handleMouseUp);
164
+ }, [handleMouseUp]);
165
+
166
+ useEventListener(
167
+ "keydown",
168
+ useCallback((e) => e.key === "Escape" && handleClose(), [handleClose]),
169
+ document
170
+ );
171
+
172
+ /* https://floating-ui.com/docs/react-dom#stable-ref-prop */
173
+ const stableRef = useMemo(() => mergeRefs([ref, refs.floating]), [
174
+ ref,
175
+ refs.floating,
176
+ ]);
177
+
178
+ if (
179
+ !children ||
180
+ children?.type === React.Fragment ||
181
+ (children as any) === React.Fragment
182
+ ) {
183
+ console.error(
184
+ "<Tooltip> children needs to be a single ReactElement and not <React.Fragment/>/<></>"
185
+ );
186
+ return null;
187
+ }
188
+
189
+ if (content?.length > maxChar) {
190
+ console.error(
191
+ `Because of strict accessibility concers we encourage all Tooltips to have less than 80 characters. Can be overwritten with the maxChar-prop`
192
+ );
193
+ return null;
194
+ }
195
+
196
+ return (
197
+ <>
198
+ {cloneElement(children, {
199
+ ...children.props,
200
+ "aria-describedby":
201
+ open || isOpen
202
+ ? cl(ariaId, children?.props["aria-describedby"])
203
+ : children?.props["aria-describedby"],
204
+ ref: mergeRefs([(children as any).ref, refs.reference]),
205
+ onMouseEnter: composeEventHandlers(
206
+ children.props.onMouseEnter,
207
+ handleDelayedOpen
208
+ ),
209
+ onMouseLeave: composeEventHandlers(
210
+ children.props.onMouseLeave,
211
+ handleClose
212
+ ),
213
+ onMouseDown: composeEventHandlers(children.props.onMouseDown, () => {
214
+ isMouseDownRef.current = true;
215
+ document.addEventListener("mouseup", handleMouseUp, { once: true });
216
+ }),
217
+ onFocus: composeEventHandlers(
218
+ children.props.onFocus,
219
+ () => !isMouseDownRef.current && handleOpen()
220
+ ),
221
+ onBlur: composeEventHandlers(children.props.onBlur, handleClose),
222
+ })}
223
+ {(open ?? isOpen) && (
224
+ <Portal>
225
+ <div
226
+ ref={stableRef}
227
+ {...rest}
228
+ onMouseEnter={handleOpen}
229
+ onMouseLeave={handleClose}
230
+ role="tooltip"
231
+ id={ariaId}
232
+ style={{
233
+ position: "absolute",
234
+ top: y ?? "",
235
+ left: x ?? "",
236
+ visibility: referenceHidden ? "hidden" : "visible",
237
+ }}
238
+ data-side={placement}
239
+ className={cl(
240
+ "navds-tooltip",
241
+ "navds-detail navds-detail--small",
242
+ className
243
+ )}
244
+ >
245
+ <div
246
+ className="navds-tooltip__inner"
247
+ style={{
248
+ [{
249
+ top: "marginBottom",
250
+ right: "marginLeft",
251
+ bottom: "marginTop",
252
+ left: "marginRight",
253
+ }[placement]]: _offset ? _offset : _arrow ? 10 : 2,
254
+ }}
255
+ >
256
+ {content}
257
+ {keys && (
258
+ <span className="navds-tooltip__keys">
259
+ {keys.map((key) => (
260
+ <Detail
261
+ size="small"
262
+ as="kbd"
263
+ key={key}
264
+ className="navds-tooltip__key"
265
+ >
266
+ {key}
267
+ </Detail>
268
+ ))}
269
+ </span>
270
+ )}
271
+ {_arrow && (
272
+ <div
273
+ ref={(node) => {
274
+ arrowRef.current = node;
275
+ }}
276
+ className="navds-tooltip__arrow"
277
+ style={{
278
+ left: arrowX != null ? `${arrowX}px` : "",
279
+ top: arrowY != null ? `${arrowY}px` : "",
280
+ right: "",
281
+ bottom: "",
282
+
283
+ [{
284
+ top: "bottom",
285
+ right: "left",
286
+ bottom: "top",
287
+ left: "right",
288
+ }[placement]]: "-3.5px",
289
+ }}
290
+ />
291
+ )}
292
+ </div>
293
+ </div>
294
+ </Portal>
295
+ )}
296
+ </>
297
+ );
298
+ }
299
+ );
300
+
301
+ export default Tooltip;
@@ -0,0 +1,2 @@
1
+ export { default as Tooltip } from "./Tooltip";
2
+ export * from "./Tooltip";
@@ -0,0 +1,15 @@
1
+ /* https://github.com/radix-ui/primitives/blob/main/packages/react/portal/src/Portal.tsx */
2
+ import ReactDOM from "react-dom";
3
+
4
+ const Portal = ({ children }) => {
5
+ const hostElement = globalThis?.document?.body;
6
+
7
+ if (hostElement) {
8
+ return ReactDOM.createPortal(children, hostElement);
9
+ }
10
+
11
+ // bail out of ssr
12
+ return null;
13
+ };
14
+
15
+ export default Portal;
@@ -0,0 +1,144 @@
1
+ import React, { useRef, useState } from "react";
2
+ import { Tooltip } from "../index";
3
+ import { Meta } from "@storybook/react/types-6-0";
4
+ import { Refresh } from "@navikt/ds-icons";
5
+ import { Button } from "../..";
6
+ import { ToggleGroup } from "../toggle-group";
7
+
8
+ export default {
9
+ title: "ds-react/tooltip",
10
+ component: Tooltip,
11
+ parameters: {
12
+ chromatic: { disable: true },
13
+ },
14
+ } as Meta;
15
+
16
+ export const Demo = () => {
17
+ const [open, setOpen] = useState(true);
18
+ const testRef = useRef(null);
19
+ return (
20
+ <div
21
+ style={{
22
+ width: "100vw",
23
+ height: "100vh",
24
+ display: "flex",
25
+ flexDirection: "column",
26
+ gap: 32,
27
+ justifyContent: "center",
28
+ alignItems: "center",
29
+ }}
30
+ >
31
+ <Tooltip
32
+ content="Tooltip example"
33
+ keys={["Cmd", "K"]}
34
+ placement="right"
35
+ open={open}
36
+ ref={testRef}
37
+ >
38
+ <Button aria-describedby="test123" onClick={() => setOpen(!open)}>
39
+ Tooltip C
40
+ </Button>
41
+ </Tooltip>
42
+ <Tooltip
43
+ content="Tooltip example"
44
+ keys={["Cmd", "K"]}
45
+ placement="right"
46
+ defaultOpen
47
+ >
48
+ <Button onClick={() => console.log(testRef.current)}>Tooltip C</Button>
49
+ </Tooltip>
50
+ <ToggleGroup onChange={null} defaultValue="321">
51
+ <Tooltip content="Tooltip" placement="bottom">
52
+ <ToggleGroup.Item value="123">Tekst</ToggleGroup.Item>
53
+ </Tooltip>
54
+ <Tooltip content="Tooltip" placement="bottom">
55
+ <ToggleGroup.Item value="321">tekst 2</ToggleGroup.Item>
56
+ </Tooltip>
57
+ <Tooltip content="Tooltip" placement="bottom">
58
+ <ToggleGroup.Item value="3212">tekst 2</ToggleGroup.Item>
59
+ </Tooltip>
60
+ <Tooltip content="Tooltip" placement="bottom">
61
+ <ToggleGroup.Item value="3213">tekst 2</ToggleGroup.Item>
62
+ </Tooltip>
63
+ <Tooltip content="Tooltip" placement="bottom">
64
+ <ToggleGroup.Item value="3214">tekst 2</ToggleGroup.Item>
65
+ </Tooltip>
66
+ </ToggleGroup>
67
+ </div>
68
+ );
69
+ };
70
+
71
+ export const All = () => {
72
+ const [open, setOpen] = useState(false);
73
+ return (
74
+ <div style={{ margin: "4rem 8rem 4rem 8rem" }}>
75
+ <h2>Controlled</h2>
76
+ <Tooltip open={open} content="Controlled tooltip example" placement="top">
77
+ <Button onClick={() => setOpen((x) => !x)}>Toggle tooltip</Button>
78
+ </Tooltip>
79
+
80
+ <h2>no arrow</h2>
81
+ <Tooltip content="no arrow" placement="top" arrow={false}>
82
+ <Button>Tooltip</Button>
83
+ </Tooltip>
84
+
85
+ <h2>Keys</h2>
86
+ <Tooltip content="Tooltip" placement="top" open keys={["Cmd", "K"]}>
87
+ <Button>Tooltip</Button>
88
+ </Tooltip>
89
+ <h2>more offset</h2>
90
+ <Tooltip content="Tooltip" placement="top" open offset={20}>
91
+ <Button>Tooltip</Button>
92
+ </Tooltip>
93
+
94
+ <h2>all placements</h2>
95
+ <div
96
+ style={{
97
+ display: "flex",
98
+ flexDirection: "column",
99
+ flexWrap: "wrap",
100
+ gap: "3rem",
101
+ }}
102
+ >
103
+ {["top", "left", "bottom", "right"].map((placement) => (
104
+ <div key={placement}>
105
+ <h3>{placement}</h3>
106
+ <div
107
+ style={{
108
+ display: "flex",
109
+ flexDirection: "column",
110
+ flexWrap: "wrap",
111
+ gap: "3rem",
112
+ }}
113
+ >
114
+ <Tooltip
115
+ key={placement}
116
+ defaultOpen
117
+ content={placement}
118
+ placement={placement as any}
119
+ >
120
+ <Refresh aria-hidden tabIndex={0} />
121
+ </Tooltip>
122
+ </div>
123
+ </div>
124
+ ))}
125
+ </div>
126
+ </div>
127
+ );
128
+ };
129
+
130
+ export const UUDemo = () => {
131
+ return (
132
+ <div>
133
+ <Button>Placeholder</Button>
134
+ <br />
135
+ <br />
136
+ <Tooltip content="Shortcut" placement="right" keys={["Cmd", "S"]}>
137
+ <Button>Lagre</Button>
138
+ </Tooltip>
139
+ <br />
140
+ <br />
141
+ <Button>Placeholder</Button>
142
+ </div>
143
+ );
144
+ };
package/src/util/index.ts CHANGED
@@ -44,3 +44,17 @@ export const useEventListener = <T extends ListenerT>(
44
44
  };
45
45
  }, [name, handler, target]);
46
46
  };
47
+
48
+ /* https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx */
49
+ export const composeEventHandlers = <E>(
50
+ originalEventHandler?: (event: E) => void,
51
+ ourEventHandler?: (event: E) => void
52
+ ) => {
53
+ return function handleEvent(event: E) {
54
+ originalEventHandler?.(event);
55
+
56
+ if (!((event as unknown) as Event).defaultPrevented) {
57
+ return ourEventHandler?.(event);
58
+ }
59
+ };
60
+ };