@hypericon/mico 0.3.21 → 0.3.24

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.
@@ -7,4 +7,6 @@ export * from "./markdown-editor";
7
7
  export * from "./menu";
8
8
  export * from "./pagination";
9
9
  export * from "./table";
10
+ export * from "./toast";
11
+ export * from "./tooltip";
10
12
  export * from "./tree";
@@ -31,6 +31,6 @@ __exportStar(require("./pagination"), exports);
31
31
  // export * from "./popover";
32
32
  // export * from "./reorderable-list";
33
33
  __exportStar(require("./table"), exports);
34
- // export * from "./toast";
35
- // export * from "./tooltip";
34
+ __exportStar(require("./toast"), exports);
35
+ __exportStar(require("./tooltip"), exports);
36
36
  __exportStar(require("./tree"), exports);
@@ -0,0 +1 @@
1
+ export * from "./toast";
@@ -1 +1,17 @@
1
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
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./toast"), exports);
@@ -0,0 +1,15 @@
1
+ import Toastify, { Options } from "toastify-js";
2
+ import m from "mithril";
3
+ import "toastify-js/src/toastify.css";
4
+ export declare const DefaultToastOptions: Partial<Options>;
5
+ /**
6
+ * Display a toast
7
+ * @param message The message string of Vnode to display
8
+ * @param options See this link for all options: https://github.com/apvarun/toastify-js#documentation
9
+ * @returns
10
+ */
11
+ export declare function toast(message: string | m.Vnode<any, any>, options?: Options): {
12
+ options: Toastify.Options;
13
+ element: Element | null;
14
+ hide: () => void;
15
+ };
@@ -0,0 +1,61 @@
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 __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.toast = exports.DefaultToastOptions = void 0;
30
+ const toastify_js_1 = __importStar(require("toastify-js"));
31
+ const mithril_1 = __importDefault(require("mithril"));
32
+ require("toastify-js/src/toastify.css");
33
+ exports.DefaultToastOptions = {
34
+ className: "mico-toast",
35
+ gravity: "bottom",
36
+ oldestFirst: true,
37
+ position: "left",
38
+ };
39
+ /**
40
+ * Display a toast
41
+ * @param message The message string of Vnode to display
42
+ * @param options See this link for all options: https://github.com/apvarun/toastify-js#documentation
43
+ * @returns
44
+ */
45
+ function toast(message, options) {
46
+ if (!message)
47
+ message = "toast";
48
+ const toastifyOpts = Object.assign({}, exports.DefaultToastOptions, options, typeof message === "string" ? { text: message } : undefined);
49
+ const toastify = (0, toastify_js_1.default)(toastifyOpts);
50
+ toastify.showToast();
51
+ if (toastify.toastElement && typeof message !== "string" && "tag" in message) {
52
+ mithril_1.default.render(toastify.toastElement, message);
53
+ (0, toastify_js_1.reposition)();
54
+ }
55
+ return {
56
+ options: toastify.options,
57
+ element: toastify.toastElement,
58
+ hide: () => toastify.hideToast(),
59
+ };
60
+ }
61
+ exports.toast = toast;
@@ -0,0 +1,3 @@
1
+ export * from "./tooltip-defaults";
2
+ export * from "./tooltip-function";
3
+ export * from "./tooltip-interfaces";
@@ -1 +1,19 @@
1
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
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./tooltip-defaults"), exports);
18
+ __exportStar(require("./tooltip-function"), exports);
19
+ __exportStar(require("./tooltip-interfaces"), exports);
@@ -0,0 +1,23 @@
1
+ import { TooltipPosition } from "./tooltip-interfaces";
2
+ export declare const TOOLTIP_DEFAULTS: {
3
+ /** How to position the tooltips by default */
4
+ DEFAULT_POS: TooltipPosition;
5
+ /** Delay in milliseconds before showing the tooltip */
6
+ DEFAULT_DELAY: number;
7
+ /** CSS class to apply to all tooltips */
8
+ TOOLTIP_CLASS: string;
9
+ /** Maximum width in pixels */
10
+ MAX_WIDTH_PX: number;
11
+ /** Maximum height in pixels */
12
+ MAX_HEIGHT_PX: number;
13
+ /** Maximum width in pixels when the "jumbo" flag is set */
14
+ MAX_WIDTH_JUMBO_PX: number;
15
+ /** Maximum height in pixels when the "jumbo" flag is set */
16
+ MAX_HEIGHT_JUMBO_PX: number;
17
+ /** Whether to attach tooltips to the document body instead of the target element */
18
+ ATTACH_TO_BODY: boolean;
19
+ /** Optionally disable tooltips globally, e.g. on touch screens */
20
+ IS_ENABLED: boolean;
21
+ /** Log debug messages to the console */
22
+ ENABLE_DEBUG: boolean;
23
+ };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TOOLTIP_DEFAULTS = void 0;
4
+ exports.TOOLTIP_DEFAULTS = {
5
+ /** How to position the tooltips by default */
6
+ DEFAULT_POS: "cursor",
7
+ /** Delay in milliseconds before showing the tooltip */
8
+ DEFAULT_DELAY: 500,
9
+ /** CSS class to apply to all tooltips */
10
+ TOOLTIP_CLASS: "mico-tooltip",
11
+ /** Maximum width in pixels */
12
+ MAX_WIDTH_PX: 250,
13
+ /** Maximum height in pixels */
14
+ MAX_HEIGHT_PX: 100,
15
+ /** Maximum width in pixels when the "jumbo" flag is set */
16
+ MAX_WIDTH_JUMBO_PX: 400,
17
+ /** Maximum height in pixels when the "jumbo" flag is set */
18
+ MAX_HEIGHT_JUMBO_PX: 300,
19
+ /** Whether to attach tooltips to the document body instead of the target element */
20
+ ATTACH_TO_BODY: false,
21
+ /** Optionally disable tooltips globally, e.g. on touch screens */
22
+ IS_ENABLED: true,
23
+ /** Log debug messages to the console */
24
+ ENABLE_DEBUG: false,
25
+ };
@@ -0,0 +1,35 @@
1
+ import { TooltipOptions } from "./tooltip-interfaces";
2
+ /**
3
+ * Display a tooltip using the given mouse event.
4
+ * Call this function from an element's "mouseenter" event.
5
+ *
6
+ * e.g.:
7
+ * ```
8
+ * onmouseenter: (ev: MouseEvent) => tooltip(ev, "Howdy!"),
9
+ * ```
10
+ * @param ev
11
+ * @param tooltip Nothing is displayed if the tooltip text is empty
12
+ * @param opts
13
+ * @returns
14
+ */
15
+ export declare function tooltip(ev: MouseEvent, tooltip: string, opts?: Partial<TooltipOptions>): void;
16
+ /**
17
+ * Return an object that can be spread into an element's attrs to add a tooltip using the mouseenter event
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * m("button", {
22
+ * ...tooltipSpread("Click the button"),
23
+ * }, "Click me"),
24
+ * // is equivalent to:
25
+ * m("button", {
26
+ * onmousenter: (ev: Mousevent) => tooltip(ev, "Click the button"),
27
+ * }, "Click me"),
28
+ * ```
29
+ * @param value
30
+ * @param opts
31
+ * @returns
32
+ */
33
+ export declare function tooltipSpread(value: string, opts?: Partial<TooltipOptions>): {
34
+ onmouseenter: (ev: MouseEvent) => void;
35
+ };
@@ -1,204 +1,205 @@
1
1
  "use strict";
2
- // import { container } from "tsyringe";
3
- // import { getLogger } from "~common/services/get-logger";
4
- // import { Logger, LogLevel } from "~common/services/logger.service";
5
- // import { MobileModeService } from "~common/services/mobile-mode.service";
6
- // const mobileMode = container.resolve(MobileModeService);
7
- // export interface TooltipOpts {
8
- // /** Specify the position of the tooltip */
9
- // pos: TooltipPos,
10
- // /** Override the default delay in milliseconds */
11
- // delay: number,
12
- // /** Increase the maximum width and height of the tooltip */
13
- // jumbo: boolean,
14
- // /** The tooltip should be attached to the document instead of the moused-over element */
15
- // attachToBody: boolean,
16
- // }
17
- // export type TooltipPos = "cursor" | "top" | "bottom" | "left" | "right" | "follow";
18
- // const DEFAULT_POS: TooltipPos = "cursor";
19
- // const DEFAULT_DELAY = 500;
20
- // const TOOLTIP_CLASS = "hypertable-tooltip";
21
- // const MAX_WIDTH_PX = 250;
22
- // const MAX_HEIGHT_PX = 100;
23
- // const MAX_WIDTH_JUMBO_PX = 400;
24
- // const MAX_HEIGHT_JUMBO_PX = 300;
25
- // const logger = getLogger("Tooltip");
26
- // // logger.logLevel = LogLevel.Debug;
27
- // /**
28
- // * Display a tooltip using the given mouse event.
29
- // * Call this function from an element's "mouseenter" event.
30
- // *
31
- // * e.g.:
32
- // * ```
33
- // * onmouseenter: (ev: MouseEvent) => tooltip(ev, "Howdy!"),
34
- // * ```
35
- // * @param ev
36
- // * @param tooltip Nothing is displayed if the tooltip text is empty
37
- // * @param opts
38
- // * @returns
39
- // */
40
- // export function tooltip(ev: MouseEvent, tooltip: string, opts?: Partial<TooltipOpts>) {
41
- // // Tooltips don't work properly in mobile mode
42
- // if (mobileMode.isMob) return;
43
- // // If there is no tooltip, don't bother
44
- // if (!tooltip) return;
45
- // const target = ev.currentTarget as HTMLElement | null;
46
- // const eventTarget = ev.target as HTMLElement | null;
47
- // logger.debug(`target is ${target?.tagName}`);
48
- // logger.debug(`event target is ${eventTarget?.tagName}`);
49
- // if (!target) {
50
- // return logger.debug("No target; returning from tooltip()");
51
- // }
52
- // // if (target?.classList.contains(TOOLTIP_CLASS) || eventTarget?.classList.contains(TOOLTIP_CLASS)) {
53
- // // return logger.debug("Target is tooltip div; returning from tooltip()");
54
- // // }
55
- // // This helps avoid re-adding tooltips when mousing over the tooltip itself
56
- // let hasTooltip = false;
57
- // target.childNodes.forEach((child, key, parent) => {
58
- // if ((child as HTMLElement)?.classList?.contains(TOOLTIP_CLASS)) {
59
- // hasTooltip = true;
60
- // }
61
- // });
62
- // if (hasTooltip) {
63
- // return logger.debug("Target already has tooltip; returning from tooltip()");
64
- // }
65
- // const mousePos = { x: ev.x, y: ev.y };
66
- // const latestPosFn = (ev: MouseEvent) => {
67
- // mousePos.x = ev.x;
68
- // mousePos.y = ev.y;
69
- // };
70
- // target.addEventListener("mousemove", latestPosFn);
71
- // const timeout = setTimeout(() => {
72
- // displayTooltip({ ev, target, tooltip, opts, mousePos });
73
- // }, opts?.delay ?? DEFAULT_DELAY);
74
- // const clearFn = (ev: MouseEvent) => {
75
- // logger.debug("Clearing tooltip timeout");
76
- // clearTimeout(timeout);
77
- // target.removeEventListener("mouseleave", clearFn);
78
- // target.removeEventListener("mousemove", latestPosFn);
79
- // };
80
- // target.addEventListener("mouseleave", clearFn);
81
- // }
82
- // /**
83
- // *
84
- // * @param value
85
- // * @param opts
86
- // * @returns
87
- // */
88
- // export function tooltipSpread(value: string, opts?: Partial<TooltipOpts>) {
89
- // return {
90
- // onmouseenter: (ev: MouseEvent) => tooltip(ev, value, opts),
91
- // };
92
- // }
93
- // /**
94
- // * TODO: consider adding arrows to top/bottom/left/right positioned tooltips
95
- // * e.g.: https://getbootstrap.com/docs/3.4/javascript/#tooltips
96
- // */
97
- // function displayTooltip(settings: {
98
- // ev: MouseEvent,
99
- // target: HTMLElement,
100
- // tooltip: string,
101
- // mousePos: { x: number, y: number, }
102
- // opts?: Partial<TooltipOpts>,
103
- // }) {
104
- // const { ev, target, tooltip, opts, mousePos } = settings;
105
- // const cursorOffsetX = 5;
106
- // const cursorOffsetY = 20;
107
- // const pos = opts?.pos ?? DEFAULT_POS;
108
- // let targetRect = target.getBoundingClientRect();
109
- // // targetRect = new DOMRect(targetRect.x, targetRect.y, targetRect.width, targetRect.height);
110
- // let targetCenter = {
111
- // x: targetRect.left + (targetRect.width / 2),
112
- // y: targetRect.top + (targetRect.height / 2),
113
- // };
114
- // const maxWidth = opts?.jumbo === true ? MAX_WIDTH_JUMBO_PX : MAX_WIDTH_PX;
115
- // const maxHeight = opts?.jumbo === true ? MAX_HEIGHT_JUMBO_PX : MAX_HEIGHT_PX;
116
- // logger.debug(`display tooltip "${tooltip}" on element ${target.tagName}`);
117
- // const tooltipEl = document.createElement("div");
118
- // tooltipEl.innerText = tooltip;
119
- // tooltipEl.classList.value = "px-2 py-1 text-xs text-dark font-normal rounded border border-primary bg-white fade-in-100 no-select";
120
- // tooltipEl.classList.add(TOOLTIP_CLASS);
121
- // tooltipEl.style.position = "fixed";
122
- // tooltipEl.style.maxWidth = `${maxWidth}px`;
123
- // tooltipEl.style.maxHeight = `${maxHeight}px`;
124
- // tooltipEl.style.zIndex = "1000";
125
- // tooltipEl.style.whiteSpace = "normal";
126
- // tooltipEl.style.opacity = "1";
127
- // tooltipEl.style.textAlign = "left";
128
- // tooltipEl.style.overflow = "hidden";
129
- // tooltipEl.setAttribute("role", "tooltip");
130
- // // // Add the tooltip before positioning it to read its dimensions
131
- // // console.log(`tooltipEl width: ${tooltipEl.clientWidth}`);
132
- // // console.log(`tooltipEl height: ${tooltipEl.clientHeight}`);
133
- // if (settings.opts?.attachToBody === true) {
134
- // document.body.append(tooltipEl);
135
- // } else {
136
- // target.append(tooltipEl);
137
- // }
138
- // // console.log(`tooltipEl width: ${tooltipEl.clientWidth}`);
139
- // // console.log(`tooltipEl height: ${tooltipEl.clientHeight}`);
140
- // if (pos === "cursor" || pos === "follow") {
141
- // tooltipEl.style.top = `${mousePos.y + cursorOffsetY}px`;
142
- // if (mousePos.x < window.innerWidth - maxWidth) {
143
- // tooltipEl.style.left = `${mousePos.x + cursorOffsetX}px`;
144
- // } else {
145
- // tooltipEl.style.right = `${document.documentElement.clientWidth - mousePos.x - cursorOffsetX}px`;
146
- // }
147
- // } else if (pos === "top") {
148
- // tooltipEl.style.bottom = `${window.innerHeight - targetRect.top}px`; // - window.scrollY
149
- // tooltipEl.style.left = `${targetCenter.x - tooltipEl.clientWidth / 2}px`;
150
- // } else if (pos === "bottom") {
151
- // tooltipEl.style.top = `${targetRect.bottom}px`; // + window.scrollY
152
- // tooltipEl.style.left = `${targetCenter.x - tooltipEl.clientWidth / 2}px`;
153
- // } else if (pos === "left") {
154
- // tooltipEl.style.right = `${document.documentElement.clientWidth - targetRect.left}px`;
155
- // tooltipEl.style.top = `${targetCenter.y - tooltipEl.clientHeight / 2}px`;
156
- // } else if (pos === "right") {
157
- // tooltipEl.style.left = `${targetRect.right}px`;
158
- // tooltipEl.style.top = `${targetCenter.y - tooltipEl.clientHeight / 2}px`;
159
- // }
160
- // if (pos === "follow") {
161
- // const followFn = (ev: MouseEvent) => {
162
- // tooltipEl.style.top = `${ev.y + cursorOffsetY}px`; // + window.scrollY
163
- // if (mousePos.x < window.innerWidth - maxWidth) {
164
- // tooltipEl.style.left = `${ev.x + cursorOffsetX}px`;
165
- // tooltipEl.style.right = "";
166
- // } else {
167
- // tooltipEl.style.right = `${document.documentElement.clientWidth - ev.x - cursorOffsetX}px`;
168
- // tooltipEl.style.left = "";
169
- // }
170
- // };
171
- // const cleanupFn = () => {
172
- // target.removeEventListener("mousemove", followFn);
173
- // target.removeEventListener("mouseleave", cleanupFn);
174
- // }
175
- // target.addEventListener("mousemove", followFn);
176
- // target.addEventListener("mouseleave", cleanupFn);
177
- // }
178
- // logger.debug(`displaying tooltip at: ${tooltipEl.style.left}, ${tooltipEl.style.top}`);
179
- // const removeFn = () => {
180
- // logger.debug(`Removing tooltip ${tooltip} from el ${target.tagName}`);
181
- // tooltipEl.onanimationend = (ev: AnimationEvent) => {
182
- // logger.debug(ev.animationName);
183
- // if (settings.opts?.attachToBody === true) {
184
- // document.body.removeChild(tooltipEl);
185
- // } else {
186
- // target.removeChild(tooltipEl);
187
- // }
188
- // }
189
- // tooltipEl.classList.replace("fade-in-100", "fade-out-100");
190
- // target.removeEventListener("mouseleave", removeFn);
191
- // tooltipEl.removeEventListener("mouseenter", removeFn);
192
- // }
193
- // target.addEventListener("mouseleave", removeFn);
194
- // tooltipEl.addEventListener("mouseenter", removeFn);
195
- // if (settings.opts?.attachToBody === true) {
196
- // const bodyListener = (ev: MouseEvent) => {
197
- // if (ev.target && !target.contains(ev.target as any)) {
198
- // removeFn();
199
- // document.body.removeEventListener("mousemove", bodyListener);
200
- // }
201
- // };
202
- // document.body.addEventListener("mousemove", bodyListener);
203
- // }
204
- // }
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tooltipSpread = exports.tooltip = void 0;
4
+ const tooltip_defaults_1 = require("./tooltip-defaults");
5
+ /**
6
+ * Display a tooltip using the given mouse event.
7
+ * Call this function from an element's "mouseenter" event.
8
+ *
9
+ * e.g.:
10
+ * ```
11
+ * onmouseenter: (ev: MouseEvent) => tooltip(ev, "Howdy!"),
12
+ * ```
13
+ * @param ev
14
+ * @param tooltip Nothing is displayed if the tooltip text is empty
15
+ * @param opts
16
+ * @returns
17
+ */
18
+ function tooltip(ev, tooltip, opts) {
19
+ var _a;
20
+ if (tooltip_defaults_1.TOOLTIP_DEFAULTS.IS_ENABLED === false)
21
+ return;
22
+ // If there is no tooltip, don't bother
23
+ if (!tooltip)
24
+ return;
25
+ const target = ev.currentTarget;
26
+ const eventTarget = ev.target;
27
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log(`target is ${target === null || target === void 0 ? void 0 : target.tagName}`);
28
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log(`event target is ${eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.tagName}`);
29
+ if (!target) {
30
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log("No target; returning from tooltip()");
31
+ return;
32
+ }
33
+ // if (target?.classList.contains(TOOLTIP_CLASS) || eventTarget?.classList.contains(TOOLTIP_CLASS)) {
34
+ // return logger.debug("Target is tooltip div; returning from tooltip()");
35
+ // }
36
+ // This helps avoid re-adding tooltips when mousing over the tooltip itself
37
+ let hasTooltip = false;
38
+ target.childNodes.forEach((child, key, parent) => {
39
+ var _a;
40
+ if ((_a = child === null || child === void 0 ? void 0 : child.classList) === null || _a === void 0 ? void 0 : _a.contains(tooltip_defaults_1.TOOLTIP_DEFAULTS.TOOLTIP_CLASS)) {
41
+ hasTooltip = true;
42
+ }
43
+ });
44
+ if (hasTooltip) {
45
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log("Target already has tooltip; returning from tooltip()");
46
+ return;
47
+ }
48
+ const mousePos = { x: ev.x, y: ev.y };
49
+ const latestPosFn = (ev) => {
50
+ mousePos.x = ev.x;
51
+ mousePos.y = ev.y;
52
+ };
53
+ target.addEventListener("mousemove", latestPosFn);
54
+ const timeout = setTimeout(() => {
55
+ displayTooltip({ ev, target, tooltip, opts, mousePos });
56
+ }, (_a = opts === null || opts === void 0 ? void 0 : opts.delay) !== null && _a !== void 0 ? _a : tooltip_defaults_1.TOOLTIP_DEFAULTS.DEFAULT_DELAY);
57
+ const clearFn = (ev) => {
58
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log("Clearing tooltip timeout");
59
+ clearTimeout(timeout);
60
+ target.removeEventListener("mouseleave", clearFn);
61
+ target.removeEventListener("mousemove", latestPosFn);
62
+ };
63
+ target.addEventListener("mouseleave", clearFn);
64
+ }
65
+ exports.tooltip = tooltip;
66
+ /**
67
+ * Return an object that can be spread into an element's attrs to add a tooltip using the mouseenter event
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * m("button", {
72
+ * ...tooltipSpread("Click the button"),
73
+ * }, "Click me"),
74
+ * // is equivalent to:
75
+ * m("button", {
76
+ * onmousenter: (ev: Mousevent) => tooltip(ev, "Click the button"),
77
+ * }, "Click me"),
78
+ * ```
79
+ * @param value
80
+ * @param opts
81
+ * @returns
82
+ */
83
+ function tooltipSpread(value, opts) {
84
+ return {
85
+ onmouseenter: (ev) => tooltip(ev, value, opts),
86
+ };
87
+ }
88
+ exports.tooltipSpread = tooltipSpread;
89
+ /**
90
+ * TODO: consider adding arrows to top/bottom/left/right positioned tooltips
91
+ * e.g.: https://getbootstrap.com/docs/3.4/javascript/#tooltips
92
+ */
93
+ function displayTooltip(settings) {
94
+ var _a, _b, _c;
95
+ const { ev, target, tooltip, opts, mousePos } = settings;
96
+ const cursorOffsetX = 5;
97
+ const cursorOffsetY = 20;
98
+ const pos = (_a = opts === null || opts === void 0 ? void 0 : opts.pos) !== null && _a !== void 0 ? _a : tooltip_defaults_1.TOOLTIP_DEFAULTS.DEFAULT_POS;
99
+ let targetRect = target.getBoundingClientRect();
100
+ // targetRect = new DOMRect(targetRect.x, targetRect.y, targetRect.width, targetRect.height);
101
+ let targetCenter = {
102
+ x: targetRect.left + (targetRect.width / 2),
103
+ y: targetRect.top + (targetRect.height / 2),
104
+ };
105
+ const maxWidth = (opts === null || opts === void 0 ? void 0 : opts.jumbo) === true ? tooltip_defaults_1.TOOLTIP_DEFAULTS.MAX_WIDTH_JUMBO_PX : tooltip_defaults_1.TOOLTIP_DEFAULTS.MAX_WIDTH_PX;
106
+ const maxHeight = (opts === null || opts === void 0 ? void 0 : opts.jumbo) === true ? tooltip_defaults_1.TOOLTIP_DEFAULTS.MAX_HEIGHT_JUMBO_PX : tooltip_defaults_1.TOOLTIP_DEFAULTS.MAX_HEIGHT_PX;
107
+ const attachToBody = (_c = (_b = settings.opts) === null || _b === void 0 ? void 0 : _b.attachToBody) !== null && _c !== void 0 ? _c : tooltip_defaults_1.TOOLTIP_DEFAULTS.ATTACH_TO_BODY;
108
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log(`display tooltip "${tooltip}" on element ${target.tagName}`);
109
+ const tooltipEl = document.createElement("div");
110
+ tooltipEl.innerText = tooltip;
111
+ // tooltipEl.classList.value = "px-2 py-1 text-xs text-dark font-normal rounded border border-primary bg-white fade-in-100 no-select";
112
+ tooltipEl.classList.add("mico-tooltip-fade-in");
113
+ tooltipEl.classList.add(tooltip_defaults_1.TOOLTIP_DEFAULTS.TOOLTIP_CLASS);
114
+ tooltipEl.style.position = "fixed";
115
+ tooltipEl.style.maxWidth = `${maxWidth}px`;
116
+ tooltipEl.style.maxHeight = `${maxHeight}px`;
117
+ tooltipEl.style.zIndex = "1000";
118
+ tooltipEl.style.whiteSpace = "normal";
119
+ tooltipEl.style.opacity = "1";
120
+ tooltipEl.style.textAlign = "left";
121
+ tooltipEl.style.overflow = "hidden";
122
+ tooltipEl.setAttribute("role", "tooltip");
123
+ // // Add the tooltip before positioning it to read its dimensions
124
+ // console.log(`tooltipEl width: ${tooltipEl.clientWidth}`);
125
+ // console.log(`tooltipEl height: ${tooltipEl.clientHeight}`);
126
+ if (attachToBody === true) {
127
+ document.body.append(tooltipEl);
128
+ }
129
+ else {
130
+ target.append(tooltipEl);
131
+ }
132
+ // console.log(`tooltipEl width: ${tooltipEl.clientWidth}`);
133
+ // console.log(`tooltipEl height: ${tooltipEl.clientHeight}`);
134
+ if (pos === "cursor" || pos === "follow") {
135
+ tooltipEl.style.top = `${mousePos.y + cursorOffsetY}px`;
136
+ if (mousePos.x < window.innerWidth - maxWidth) {
137
+ tooltipEl.style.left = `${mousePos.x + cursorOffsetX}px`;
138
+ }
139
+ else {
140
+ tooltipEl.style.right = `${document.documentElement.clientWidth - mousePos.x - cursorOffsetX}px`;
141
+ }
142
+ }
143
+ else if (pos === "top") {
144
+ tooltipEl.style.bottom = `${window.innerHeight - targetRect.top}px`; // - window.scrollY
145
+ tooltipEl.style.left = `${targetCenter.x - tooltipEl.clientWidth / 2}px`;
146
+ }
147
+ else if (pos === "bottom") {
148
+ tooltipEl.style.top = `${targetRect.bottom}px`; // + window.scrollY
149
+ tooltipEl.style.left = `${targetCenter.x - tooltipEl.clientWidth / 2}px`;
150
+ }
151
+ else if (pos === "left") {
152
+ tooltipEl.style.right = `${document.documentElement.clientWidth - targetRect.left}px`;
153
+ tooltipEl.style.top = `${targetCenter.y - tooltipEl.clientHeight / 2}px`;
154
+ }
155
+ else if (pos === "right") {
156
+ tooltipEl.style.left = `${targetRect.right}px`;
157
+ tooltipEl.style.top = `${targetCenter.y - tooltipEl.clientHeight / 2}px`;
158
+ }
159
+ if (pos === "follow") {
160
+ const followFn = (ev) => {
161
+ tooltipEl.style.top = `${ev.y + cursorOffsetY}px`; // + window.scrollY
162
+ if (mousePos.x < window.innerWidth - maxWidth) {
163
+ tooltipEl.style.left = `${ev.x + cursorOffsetX}px`;
164
+ tooltipEl.style.right = "";
165
+ }
166
+ else {
167
+ tooltipEl.style.right = `${document.documentElement.clientWidth - ev.x - cursorOffsetX}px`;
168
+ tooltipEl.style.left = "";
169
+ }
170
+ };
171
+ const cleanupFn = () => {
172
+ target.removeEventListener("mousemove", followFn);
173
+ target.removeEventListener("mouseleave", cleanupFn);
174
+ };
175
+ target.addEventListener("mousemove", followFn);
176
+ target.addEventListener("mouseleave", cleanupFn);
177
+ }
178
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log(`displaying tooltip at: ${tooltipEl.style.left}, ${tooltipEl.style.top}`);
179
+ const removeFn = () => {
180
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log(`Removing tooltip ${tooltip} from el ${target.tagName}`);
181
+ tooltipEl.onanimationend = (ev) => {
182
+ tooltip_defaults_1.TOOLTIP_DEFAULTS.ENABLE_DEBUG && console.log(ev.animationName);
183
+ if (attachToBody === true) {
184
+ document.body.removeChild(tooltipEl);
185
+ }
186
+ else {
187
+ target.removeChild(tooltipEl);
188
+ }
189
+ };
190
+ tooltipEl.classList.replace("mico-tooltip-fade-in", "mico-tooltip-fade-out");
191
+ target.removeEventListener("mouseleave", removeFn);
192
+ tooltipEl.removeEventListener("mouseenter", removeFn);
193
+ };
194
+ target.addEventListener("mouseleave", removeFn);
195
+ tooltipEl.addEventListener("mouseenter", removeFn);
196
+ if (attachToBody === true) {
197
+ const bodyListener = (ev) => {
198
+ if (ev.target && !target.contains(ev.target)) {
199
+ removeFn();
200
+ document.body.removeEventListener("mousemove", bodyListener);
201
+ }
202
+ };
203
+ document.body.addEventListener("mousemove", bodyListener);
204
+ }
205
+ }
@@ -0,0 +1,11 @@
1
+ export interface TooltipOptions {
2
+ /** Specify the position of the tooltip */
3
+ pos: TooltipPosition;
4
+ /** Override the default delay in milliseconds */
5
+ delay: number;
6
+ /** Increase the maximum width and height of the tooltip */
7
+ jumbo: boolean;
8
+ /** The tooltip should be attached to the document instead of the moused-over element */
9
+ attachToBody: boolean;
10
+ }
11
+ export type TooltipPosition = "cursor" | "top" | "bottom" | "left" | "right" | "follow";
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypericon/mico",
3
- "version": "0.3.21",
3
+ "version": "0.3.24",
4
4
  "description": "UI components and utilities with Mithril",
5
5
  "author": "Ed Johnson, Hypericon Ltd",
6
6
  "license": "MIT",
@@ -24,13 +24,15 @@
24
24
  "highlight.js": "^11.8.0",
25
25
  "marked": "^4.3.0",
26
26
  "mithril": "^2.2.2",
27
- "rxjs": "^7.8.1"
27
+ "rxjs": "^7.8.1",
28
+ "toastify-js": "^1.12.0"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@types/dompurify": "^3.0.2",
31
32
  "@types/marked": "^4.3.0",
32
33
  "@types/mithril": "^2.0.12",
33
34
  "@types/node": "^20.1.4",
35
+ "@types/toastify-js": "^1.11.1",
34
36
  "rimraf": "^5.0.0",
35
37
  "typescript": "^5.0.4",
36
38
  "vite": "^4.3.5"