@hypericon/mico 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -1
- package/dist/components/menu/Menu.d.ts +7 -0
- package/dist/components/menu/Menu.js +79 -0
- package/dist/components/menu/MenuButton.d.ts +16 -0
- package/dist/components/menu/MenuButton.js +81 -0
- package/dist/components/menu/MenuSeparator.d.ts +2 -0
- package/dist/components/menu/MenuSeparator.js +17 -0
- package/dist/components/menu/index.d.ts +6 -0
- package/dist/components/menu/index.js +21 -0
- package/dist/components/menu/menu-constants.d.ts +4 -0
- package/dist/components/menu/menu-constants.js +7 -0
- package/dist/components/menu/menu-service.d.ts +21 -0
- package/dist/components/menu/menu-service.js +78 -0
- package/dist/components/menu/menu-settings.d.ts +9 -0
- package/dist/components/menu/menu-settings.js +12 -0
- package/package.json +3 -2
package/dist/components/index.js
CHANGED
|
@@ -21,7 +21,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
21
21
|
// export * from "./form";
|
|
22
22
|
__exportStar(require("./icon"), exports);
|
|
23
23
|
__exportStar(require("./markdown"), exports);
|
|
24
|
-
|
|
24
|
+
__exportStar(require("./menu"), exports);
|
|
25
25
|
// export * from "./modal";
|
|
26
26
|
// export * from "./pagination";
|
|
27
27
|
// export * from "./popover";
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
exports.Menu = void 0;
|
|
7
|
+
const mithril_1 = __importDefault(require("mithril"));
|
|
8
|
+
const menu_constants_1 = require("./menu-constants");
|
|
9
|
+
const menu_settings_1 = require("./menu-settings");
|
|
10
|
+
exports.Menu = {
|
|
11
|
+
oninit() { },
|
|
12
|
+
oncreate({ dom }) {
|
|
13
|
+
if (dom) {
|
|
14
|
+
this.el = dom;
|
|
15
|
+
this.el.focus();
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
onupdate({ dom }) {
|
|
19
|
+
// if (dom) this.el = dom as HTMLDivElement;
|
|
20
|
+
},
|
|
21
|
+
view({ attrs, children, }) {
|
|
22
|
+
var _a, _b;
|
|
23
|
+
const maxWidthPx = Math.min(window.innerWidth, menu_constants_1.MENU_CONSTANTS.MAX_WIDTH_PX);
|
|
24
|
+
const maxHeightPx = window.innerHeight / 2;
|
|
25
|
+
const xPx = (_a = attrs.x) !== null && _a !== void 0 ? _a : 0;
|
|
26
|
+
const yPx = (_b = attrs.y) !== null && _b !== void 0 ? _b : 0;
|
|
27
|
+
const flipH = ((xPx + menu_constants_1.MENU_CONSTANTS.MIN_WIDTH_PX) > window.innerWidth);
|
|
28
|
+
const flipV = menu_settings_1.MENU_SETTINGS.ANCHOR === "page"
|
|
29
|
+
? ((yPx + maxHeightPx - window.scrollY) > window.innerHeight)
|
|
30
|
+
: ((yPx + maxHeightPx) > window.innerHeight);
|
|
31
|
+
// console.log({
|
|
32
|
+
// "yPx": yPx,
|
|
33
|
+
// "maxHeightPx": maxHeightPx,
|
|
34
|
+
// "window.scrollY": window.scrollY,
|
|
35
|
+
// "window.innerHeight": window.innerHeight,
|
|
36
|
+
// "flipV": flipV,
|
|
37
|
+
// });
|
|
38
|
+
// TODO: don't let the menu width actually touch the screen width; it will fall off the left hand side
|
|
39
|
+
const posH = flipH ? `right: ${window.innerWidth - xPx}px;` : `left: ${xPx}px;`;
|
|
40
|
+
const posV = flipV ? `bottom: ${window.innerHeight - yPx}px;` : `top: ${yPx}px;`;
|
|
41
|
+
return (0, mithril_1.default)("", {
|
|
42
|
+
key: Date.now(),
|
|
43
|
+
class: menu_settings_1.MENU_SETTINGS.MENU_CLASS,
|
|
44
|
+
style: `position: absolute; overflow-y: auto; overflow-x: hidden; ${posH} ${posV} z-index: 100; min-width: ${menu_constants_1.MENU_CONSTANTS.MIN_WIDTH_PX}px; max-width: ${maxWidthPx}px; max-height: ${maxHeightPx}px;`,
|
|
45
|
+
tabIndex: -1,
|
|
46
|
+
onkeydown: (ev) => {
|
|
47
|
+
var _a, _b, _c, _d, _e, _f;
|
|
48
|
+
const focussableElems = Array.from((_b = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelectorAll("button, input, select, textarea")) !== null && _b !== void 0 ? _b : [])
|
|
49
|
+
.filter(el => !Boolean(el.disabled));
|
|
50
|
+
let focusIndex = -1;
|
|
51
|
+
if (focussableElems) {
|
|
52
|
+
for (let i = 0; i < focussableElems.length; i++) {
|
|
53
|
+
const element = focussableElems[i];
|
|
54
|
+
if (document.activeElement === element) {
|
|
55
|
+
focusIndex = i;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (ev.key === "ArrowDown") {
|
|
61
|
+
// console.log("move down, focussable list:", focussableElems, "this.el", this.el);
|
|
62
|
+
focusIndex += 1;
|
|
63
|
+
if (focusIndex >= focussableElems.length)
|
|
64
|
+
focusIndex = 0;
|
|
65
|
+
(_d = (_c = focussableElems[focusIndex]).focus) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
66
|
+
}
|
|
67
|
+
if (ev.key === "ArrowUp") {
|
|
68
|
+
// console.log("move up, focussable list:", focussableElems, "this.el", this.el);
|
|
69
|
+
focusIndex -= 1;
|
|
70
|
+
if (focusIndex < 0)
|
|
71
|
+
focusIndex = focussableElems.length - 1;
|
|
72
|
+
(_f = (_e = focussableElems[focusIndex]).focus) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
}, [
|
|
76
|
+
children,
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
import { IconAttrs } from "../icon";
|
|
3
|
+
export declare const MenuButton: m.Component<{
|
|
4
|
+
icon?: m.Vnode<any, any> | IconAttrs;
|
|
5
|
+
label?: string;
|
|
6
|
+
hint?: string;
|
|
7
|
+
/** If an href is supplied, `m.route.Link` is used instad of `button` */
|
|
8
|
+
href?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
onclick?: (ev: MouseEvent) => any;
|
|
11
|
+
onhover?: (ev: MouseEvent) => any;
|
|
12
|
+
onprev?: (ev: KeyboardEvent) => any;
|
|
13
|
+
onnext?: (ev: KeyboardEvent) => any;
|
|
14
|
+
class?: string;
|
|
15
|
+
style?: string;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
exports.MenuButton = void 0;
|
|
7
|
+
const mithril_1 = __importDefault(require("mithril"));
|
|
8
|
+
const icon_1 = require("../icon");
|
|
9
|
+
const menu_settings_1 = require("./menu-settings");
|
|
10
|
+
exports.MenuButton = {
|
|
11
|
+
view({ attrs }) {
|
|
12
|
+
var _a, _b, _c, _d;
|
|
13
|
+
return (attrs.href !== undefined) ? [
|
|
14
|
+
(0, mithril_1.default)(mithril_1.default.route.Link, {
|
|
15
|
+
class: `${(_a = attrs.class) !== null && _a !== void 0 ? _a : ""} ${menu_settings_1.MENU_SETTINGS.MENU_BUTTON_CLASS}`,
|
|
16
|
+
style: `${(_b = attrs.style) !== null && _b !== void 0 ? _b : ""} width: 100%; height: 1.5rem; padding-right: 0.5rem; display: flex; align-items: center;`,
|
|
17
|
+
href: attrs.href,
|
|
18
|
+
disabled: attrs.disabled,
|
|
19
|
+
onclick: (ev) => {
|
|
20
|
+
var _a;
|
|
21
|
+
(_a = attrs.onclick) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
|
|
22
|
+
mithril_1.default.redraw();
|
|
23
|
+
},
|
|
24
|
+
}, [
|
|
25
|
+
(0, mithril_1.default)(ButtonIcon, { icon: attrs.icon }),
|
|
26
|
+
(0, mithril_1.default)(ButtonLabel, { label: attrs.label }),
|
|
27
|
+
(0, mithril_1.default)("", { style: "flex: 1 1 0%;" }),
|
|
28
|
+
(0, mithril_1.default)(ButtonHint, { hint: attrs.hint }),
|
|
29
|
+
]),
|
|
30
|
+
] : [
|
|
31
|
+
(0, mithril_1.default)("button", {
|
|
32
|
+
class: `${(_c = attrs.class) !== null && _c !== void 0 ? _c : ""} ${menu_settings_1.MENU_SETTINGS.MENU_BUTTON_CLASS}`,
|
|
33
|
+
style: `${(_d = attrs.style) !== null && _d !== void 0 ? _d : ""} width: 100%; height: 1.5rem; padding-right: 0.5rem; display: flex; align-items: center;`,
|
|
34
|
+
disabled: attrs.disabled,
|
|
35
|
+
onclick: (ev) => {
|
|
36
|
+
var _a;
|
|
37
|
+
(_a = attrs.onclick) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
|
|
38
|
+
mithril_1.default.redraw();
|
|
39
|
+
},
|
|
40
|
+
}, [
|
|
41
|
+
(0, mithril_1.default)(ButtonIcon, { icon: attrs.icon }),
|
|
42
|
+
(0, mithril_1.default)(ButtonLabel, { label: attrs.label }),
|
|
43
|
+
(0, mithril_1.default)("", { style: "flex: 1 1 0%;" }),
|
|
44
|
+
(0, mithril_1.default)(ButtonHint, { hint: attrs.hint }),
|
|
45
|
+
]),
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const ButtonIcon = {
|
|
50
|
+
view({ attrs }) {
|
|
51
|
+
return (0, mithril_1.default)("", {
|
|
52
|
+
// class: attrs.disabled ? "text-disabled" : "text-icon",
|
|
53
|
+
class: menu_settings_1.MENU_SETTINGS.MENU_BUTTON_ICON_CLASS,
|
|
54
|
+
style: "width: 2rem; flex: none; display: flex; align-items: center; justify-content: space-around;",
|
|
55
|
+
}, [
|
|
56
|
+
attrs.icon ? [
|
|
57
|
+
("fas" in attrs.icon || "far" in attrs.icon || "fab" in attrs.icon)
|
|
58
|
+
? (0, mithril_1.default)(icon_1.Icon, Object.assign({}, attrs.icon))
|
|
59
|
+
: attrs.icon,
|
|
60
|
+
] : [],
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const ButtonLabel = {
|
|
65
|
+
view({ attrs }) {
|
|
66
|
+
return (0, mithril_1.default)("span", {
|
|
67
|
+
class: menu_settings_1.MENU_SETTINGS.MENU_BUTTON_LABEL_CLASS,
|
|
68
|
+
style: "overflow: hidden; text-overflow: ellipsis; white-space: nowrap;",
|
|
69
|
+
}, attrs.label);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const ButtonHint = {
|
|
73
|
+
view({ attrs }) {
|
|
74
|
+
return attrs.hint
|
|
75
|
+
? (0, mithril_1.default)("span", {
|
|
76
|
+
class: menu_settings_1.MENU_SETTINGS.MENU_BUTTON_HINT_CLASS,
|
|
77
|
+
style: "overflow: hidden; text-overflow: ellipsis; white-space: nowrap;",
|
|
78
|
+
}, attrs.hint)
|
|
79
|
+
: [];
|
|
80
|
+
}
|
|
81
|
+
};
|
|
@@ -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
|
+
exports.MenuSeparator = void 0;
|
|
7
|
+
const mithril_1 = __importDefault(require("mithril"));
|
|
8
|
+
const menu_settings_1 = require("./menu-settings");
|
|
9
|
+
exports.MenuSeparator = {
|
|
10
|
+
view() {
|
|
11
|
+
// return m(".my-2.ml-8.mr-2.border-b.border-slate-300");
|
|
12
|
+
return (0, mithril_1.default)("", {
|
|
13
|
+
class: menu_settings_1.MENU_SETTINGS.MENU_SEPARATOR_CLASS,
|
|
14
|
+
style: "margin: 0.25rem 0; border-bottom: 1px;",
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -1 +1,22 @@
|
|
|
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("./Menu"), exports);
|
|
18
|
+
__exportStar(require("./MenuButton"), exports);
|
|
19
|
+
__exportStar(require("./MenuSeparator"), exports);
|
|
20
|
+
__exportStar(require("./menu-constants"), exports);
|
|
21
|
+
__exportStar(require("./menu-service"), exports);
|
|
22
|
+
__exportStar(require("./menu-settings"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
export declare class MenuService {
|
|
3
|
+
private containerEl;
|
|
4
|
+
private _menuVnode;
|
|
5
|
+
menuVnode$: import("rxjs").Observable<m.Vnode<any, any> | undefined>;
|
|
6
|
+
get menuVnode(): m.Vnode<any, any> | undefined;
|
|
7
|
+
get isOpen(): boolean;
|
|
8
|
+
constructor();
|
|
9
|
+
/**
|
|
10
|
+
* Show a new "right-click" menu at the position of the given mouse event,
|
|
11
|
+
* containing the given menu contents.
|
|
12
|
+
*
|
|
13
|
+
* This function handles stopping the mouse event propagation and aiting for any previous menus
|
|
14
|
+
* to be cleared.
|
|
15
|
+
* @param ev
|
|
16
|
+
* @param menuContents
|
|
17
|
+
*/
|
|
18
|
+
show(ev: MouseEvent | undefined, menuContents: m.ChildArrayOrPrimitive): Promise<void>;
|
|
19
|
+
hide(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare const menuService: MenuService;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.menuService = exports.MenuService = void 0;
|
|
16
|
+
const mithril_1 = __importDefault(require("mithril"));
|
|
17
|
+
const rxjs_1 = require("rxjs");
|
|
18
|
+
const Menu_1 = require("./Menu");
|
|
19
|
+
const menu_settings_1 = require("./menu-settings");
|
|
20
|
+
class MenuService {
|
|
21
|
+
get menuVnode() { return this._menuVnode.value; }
|
|
22
|
+
get isOpen() {
|
|
23
|
+
return Boolean(this.menuVnode);
|
|
24
|
+
}
|
|
25
|
+
constructor() {
|
|
26
|
+
this._menuVnode = new rxjs_1.BehaviorSubject(undefined);
|
|
27
|
+
this.menuVnode$ = this._menuVnode.asObservable();
|
|
28
|
+
this.containerEl = document.createElement("div");
|
|
29
|
+
this.containerEl.classList.add("menu-container");
|
|
30
|
+
document.body.append(this.containerEl);
|
|
31
|
+
document.addEventListener("click", () => {
|
|
32
|
+
if (this.isOpen) {
|
|
33
|
+
this.hide();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
document.addEventListener("keydown", (ev) => {
|
|
37
|
+
if (this.isOpen && (ev.key === "Escape")) {
|
|
38
|
+
this.hide();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Show a new "right-click" menu at the position of the given mouse event,
|
|
44
|
+
* containing the given menu contents.
|
|
45
|
+
*
|
|
46
|
+
* This function handles stopping the mouse event propagation and aiting for any previous menus
|
|
47
|
+
* to be cleared.
|
|
48
|
+
* @param ev
|
|
49
|
+
* @param menuContents
|
|
50
|
+
*/
|
|
51
|
+
show(ev, menuContents) {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
ev === null || ev === void 0 ? void 0 : ev.stopPropagation();
|
|
54
|
+
if (this.isOpen) {
|
|
55
|
+
this.hide();
|
|
56
|
+
}
|
|
57
|
+
yield new Promise((resolve, reject) => {
|
|
58
|
+
setTimeout(() => resolve(), 0);
|
|
59
|
+
});
|
|
60
|
+
const menuVnode = (0, mithril_1.default)(Menu_1.Menu, {
|
|
61
|
+
x: ev === null || ev === void 0 ? void 0 : ev.clientX,
|
|
62
|
+
y: menu_settings_1.MENU_SETTINGS.ANCHOR === "page" ? ev === null || ev === void 0 ? void 0 : ev.pageY : ev === null || ev === void 0 ? void 0 : ev.clientY,
|
|
63
|
+
}, [
|
|
64
|
+
menuContents,
|
|
65
|
+
]);
|
|
66
|
+
this._menuVnode.next(menuVnode);
|
|
67
|
+
mithril_1.default.render(this.containerEl, menuVnode);
|
|
68
|
+
// console.log("Added menu");
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
hide() {
|
|
72
|
+
this._menuVnode.next(undefined);
|
|
73
|
+
mithril_1.default.render(this.containerEl, []);
|
|
74
|
+
// console.log("Closed menu");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.MenuService = MenuService;
|
|
78
|
+
exports.menuService = new MenuService();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MENU_SETTINGS = void 0;
|
|
4
|
+
exports.MENU_SETTINGS = {
|
|
5
|
+
ANCHOR: "page",
|
|
6
|
+
MENU_CLASS: "",
|
|
7
|
+
MENU_BUTTON_CLASS: "",
|
|
8
|
+
MENU_BUTTON_LABEL_CLASS: "",
|
|
9
|
+
MENU_BUTTON_ICON_CLASS: "",
|
|
10
|
+
MENU_BUTTON_HINT_CLASS: "",
|
|
11
|
+
MENU_SEPARATOR_CLASS: "",
|
|
12
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypericon/mico",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "UI components and utilities with Mithril",
|
|
5
5
|
"author": "Ed Johnson, Hypericon Ltd",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"dompurify": "^3.0.3",
|
|
21
21
|
"highlight.js": "^11.8.0",
|
|
22
22
|
"marked": "^4.3.0",
|
|
23
|
-
"mithril": "^2.2.2"
|
|
23
|
+
"mithril": "^2.2.2",
|
|
24
|
+
"rxjs": "^7.8.1"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@types/dompurify": "^3.0.2",
|