@hypericon/mico 0.5.10 → 0.5.12
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/cjs/components/menu/Menu.d.ts +23 -3
- package/dist/cjs/components/menu/Menu.js +9 -0
- package/dist/cjs/components/menu/MenuButton.js +4 -0
- package/dist/cjs/components/menu/MenuSeparator.js +2 -0
- package/dist/cjs/components/menu/menu-manager.d.ts +1 -0
- package/dist/cjs/components/menu/menu-manager.js +13 -1
- package/dist/cjs/components/table/Table.d.ts +1 -1
- package/dist/esm/components/menu/Menu.d.ts +23 -3
- package/dist/esm/components/menu/Menu.js +9 -0
- package/dist/esm/components/menu/MenuButton.js +4 -0
- package/dist/esm/components/menu/MenuSeparator.js +2 -0
- package/dist/esm/components/menu/menu-manager.d.ts +1 -0
- package/dist/esm/components/menu/menu-manager.js +13 -1
- package/dist/esm/components/table/Table.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import m from "mithril";
|
|
2
2
|
export interface MenuOptions {
|
|
3
|
+
/** Prevent vertical flipping when menu would go off-screen at the bottom */
|
|
3
4
|
noFlipV?: boolean;
|
|
5
|
+
/** Prevent horizontal flipping when menu would go off-screen at the right edge */
|
|
4
6
|
noFlipH?: boolean;
|
|
7
|
+
/** Force the menu to flip vertically regardless of available space */
|
|
5
8
|
forceFlipV?: boolean;
|
|
9
|
+
/** Force the menu to flip horizontally regardless of available space */
|
|
6
10
|
forceFlipH?: boolean;
|
|
7
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Add the menu directly to the element which raised the event, rather than
|
|
13
|
+
* to the global menu container
|
|
14
|
+
*/
|
|
8
15
|
asChild?: boolean;
|
|
9
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Display the menu using an HTMLDialogElement instead of a standard div.
|
|
18
|
+
* Useful for complex stacking contexts.
|
|
19
|
+
*/
|
|
10
20
|
asDialog?: boolean;
|
|
11
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Indicates the menu is within a dialog element and should be displayed with
|
|
23
|
+
* fixed positioning relative to the dialog
|
|
24
|
+
*/
|
|
12
25
|
isWithinDialog?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Keep menu open when clicking within it. Useful for menus with toggle switches
|
|
28
|
+
* or radio buttons where users want to try multiple options without reopening the menu.
|
|
29
|
+
* The menu will still close when clicking outside or pressing Escape.
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
keepOpenOnClick?: boolean;
|
|
13
33
|
}
|
|
14
34
|
export declare const Menu: m.Component<{
|
|
15
35
|
x: number | undefined;
|
|
@@ -58,7 +58,16 @@ exports.Menu = {
|
|
|
58
58
|
key: Date.now(),
|
|
59
59
|
class: `mico-menu ${menu_settings_1.MENU_SETTINGS.MENU_CLASS}`,
|
|
60
60
|
style: `position: ${position}; 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;`,
|
|
61
|
+
role: "menu",
|
|
62
|
+
"aria-orientation": "vertical",
|
|
61
63
|
tabIndex: -1,
|
|
64
|
+
onclick: (ev) => {
|
|
65
|
+
var _a;
|
|
66
|
+
// Prevent clicks within the menu from propagating when keepOpenOnClick is enabled
|
|
67
|
+
if ((_a = attrs.options) === null || _a === void 0 ? void 0 : _a.keepOpenOnClick) {
|
|
68
|
+
ev.stopPropagation();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
62
71
|
onkeydown: (ev) => {
|
|
63
72
|
var _a, _b, _c, _d, _e, _f;
|
|
64
73
|
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 : [])
|
|
@@ -14,8 +14,10 @@ exports.MenuButton = {
|
|
|
14
14
|
(0, mithril_1.default)(mithril_1.default.route.Link, {
|
|
15
15
|
class: `mico-menu-button ${(_a = attrs.class) !== null && _a !== void 0 ? _a : ""} ${menu_settings_1.MENU_SETTINGS.MENU_BUTTON_CLASS}`,
|
|
16
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
|
+
role: "menuitem",
|
|
17
18
|
href: attrs.href,
|
|
18
19
|
disabled: attrs.disabled,
|
|
20
|
+
"aria-disabled": attrs.disabled ? "true" : undefined,
|
|
19
21
|
onclick: (ev) => {
|
|
20
22
|
var _a;
|
|
21
23
|
(_a = attrs.onclick) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
|
|
@@ -31,7 +33,9 @@ exports.MenuButton = {
|
|
|
31
33
|
(0, mithril_1.default)("button", {
|
|
32
34
|
class: `mico-menu-button ${(_c = attrs.class) !== null && _c !== void 0 ? _c : ""} ${menu_settings_1.MENU_SETTINGS.MENU_BUTTON_CLASS}`,
|
|
33
35
|
style: `${(_d = attrs.style) !== null && _d !== void 0 ? _d : ""} width: 100%; height: 1.5rem; padding-right: 0.5rem; display: flex; align-items: center;`,
|
|
36
|
+
role: "menuitem",
|
|
34
37
|
disabled: attrs.disabled,
|
|
38
|
+
"aria-disabled": attrs.disabled ? "true" : undefined,
|
|
35
39
|
onclick: (ev) => {
|
|
36
40
|
var _a;
|
|
37
41
|
(_a = attrs.onclick) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
|
|
@@ -12,6 +12,8 @@ exports.MenuSeparator = {
|
|
|
12
12
|
return (0, mithril_1.default)("", {
|
|
13
13
|
class: `mico-menu-separator ${menu_settings_1.MENU_SETTINGS.MENU_SEPARATOR_CLASS}`,
|
|
14
14
|
style: "margin: 0.25rem 0; border-bottom-width: 1px; border-bottom-style: solid;",
|
|
15
|
+
role: "separator",
|
|
16
|
+
"aria-orientation": "horizontal",
|
|
15
17
|
});
|
|
16
18
|
}
|
|
17
19
|
};
|
|
@@ -29,8 +29,18 @@ class MenuManager {
|
|
|
29
29
|
this.containerEl = document.createElement("div");
|
|
30
30
|
this.containerEl.classList.add("menu-container");
|
|
31
31
|
document.body.append(this.containerEl);
|
|
32
|
-
document.addEventListener("click", () => {
|
|
32
|
+
document.addEventListener("click", (ev) => {
|
|
33
|
+
var _a;
|
|
33
34
|
if (this.isOpen) {
|
|
35
|
+
// If keepOpenOnClick is enabled, check if the click is within the menu
|
|
36
|
+
if ((_a = this.currentOptions) === null || _a === void 0 ? void 0 : _a.keepOpenOnClick) {
|
|
37
|
+
const target = ev.target;
|
|
38
|
+
const clickedInMenu = target.closest(".mico-menu");
|
|
39
|
+
if (clickedInMenu) {
|
|
40
|
+
menu_settings_1.MENU_SETTINGS.DEBUG_MENU && console.log("Click within menu, keeping open (keepOpenOnClick=true)");
|
|
41
|
+
return; // Don't close the menu
|
|
42
|
+
}
|
|
43
|
+
}
|
|
34
44
|
this.hide();
|
|
35
45
|
}
|
|
36
46
|
});
|
|
@@ -106,6 +116,7 @@ class MenuManager {
|
|
|
106
116
|
menuContents,
|
|
107
117
|
]);
|
|
108
118
|
this._menuVnode.next(menuVnode);
|
|
119
|
+
this.currentOptions = options;
|
|
109
120
|
// If the menu is to be shown as a dialog, we need to mount it to a dialog element
|
|
110
121
|
if (options === null || options === void 0 ? void 0 : options.asDialog) {
|
|
111
122
|
// this.dialogEl = document.createElement("dialog");
|
|
@@ -158,6 +169,7 @@ class MenuManager {
|
|
|
158
169
|
this.directParentEl = undefined;
|
|
159
170
|
(_b = this.dialogEl) === null || _b === void 0 ? void 0 : _b.close();
|
|
160
171
|
mithril_1.default.render(this.dialogEl, []);
|
|
172
|
+
this.currentOptions = undefined;
|
|
161
173
|
menu_settings_1.MENU_SETTINGS.DEBUG_MENU && console.log("Closed menu");
|
|
162
174
|
}
|
|
163
175
|
/**
|
|
@@ -35,7 +35,7 @@ export interface TableState<T> {
|
|
|
35
35
|
/** Helper function to make it easier to define table columns */
|
|
36
36
|
export type TableColumnDefinitionFn<T> = (
|
|
37
37
|
/** The label or other element to display in the header */
|
|
38
|
-
header:
|
|
38
|
+
header: m.Children,
|
|
39
39
|
/** Function defining how to display a cell in the column using the given row item */
|
|
40
40
|
cell: TableCellDisplayFn<T>,
|
|
41
41
|
/** Optional settings to tweak the column's behaviour */
|
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import m from "mithril";
|
|
2
2
|
export interface MenuOptions {
|
|
3
|
+
/** Prevent vertical flipping when menu would go off-screen at the bottom */
|
|
3
4
|
noFlipV?: boolean;
|
|
5
|
+
/** Prevent horizontal flipping when menu would go off-screen at the right edge */
|
|
4
6
|
noFlipH?: boolean;
|
|
7
|
+
/** Force the menu to flip vertically regardless of available space */
|
|
5
8
|
forceFlipV?: boolean;
|
|
9
|
+
/** Force the menu to flip horizontally regardless of available space */
|
|
6
10
|
forceFlipH?: boolean;
|
|
7
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Add the menu directly to the element which raised the event, rather than
|
|
13
|
+
* to the global menu container
|
|
14
|
+
*/
|
|
8
15
|
asChild?: boolean;
|
|
9
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Display the menu using an HTMLDialogElement instead of a standard div.
|
|
18
|
+
* Useful for complex stacking contexts.
|
|
19
|
+
*/
|
|
10
20
|
asDialog?: boolean;
|
|
11
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Indicates the menu is within a dialog element and should be displayed with
|
|
23
|
+
* fixed positioning relative to the dialog
|
|
24
|
+
*/
|
|
12
25
|
isWithinDialog?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Keep menu open when clicking within it. Useful for menus with toggle switches
|
|
28
|
+
* or radio buttons where users want to try multiple options without reopening the menu.
|
|
29
|
+
* The menu will still close when clicking outside or pressing Escape.
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
keepOpenOnClick?: boolean;
|
|
13
33
|
}
|
|
14
34
|
export declare const Menu: m.Component<{
|
|
15
35
|
x: number | undefined;
|
|
@@ -58,7 +58,16 @@ exports.Menu = {
|
|
|
58
58
|
key: Date.now(),
|
|
59
59
|
class: `mico-menu ${menu_settings_1.MENU_SETTINGS.MENU_CLASS}`,
|
|
60
60
|
style: `position: ${position}; 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;`,
|
|
61
|
+
role: "menu",
|
|
62
|
+
"aria-orientation": "vertical",
|
|
61
63
|
tabIndex: -1,
|
|
64
|
+
onclick: (ev) => {
|
|
65
|
+
var _a;
|
|
66
|
+
// Prevent clicks within the menu from propagating when keepOpenOnClick is enabled
|
|
67
|
+
if ((_a = attrs.options) === null || _a === void 0 ? void 0 : _a.keepOpenOnClick) {
|
|
68
|
+
ev.stopPropagation();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
62
71
|
onkeydown: (ev) => {
|
|
63
72
|
var _a, _b, _c, _d, _e, _f;
|
|
64
73
|
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 : [])
|
|
@@ -14,8 +14,10 @@ exports.MenuButton = {
|
|
|
14
14
|
(0, mithril_1.default)(mithril_1.default.route.Link, {
|
|
15
15
|
class: `mico-menu-button ${(_a = attrs.class) !== null && _a !== void 0 ? _a : ""} ${menu_settings_1.MENU_SETTINGS.MENU_BUTTON_CLASS}`,
|
|
16
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
|
+
role: "menuitem",
|
|
17
18
|
href: attrs.href,
|
|
18
19
|
disabled: attrs.disabled,
|
|
20
|
+
"aria-disabled": attrs.disabled ? "true" : undefined,
|
|
19
21
|
onclick: (ev) => {
|
|
20
22
|
var _a;
|
|
21
23
|
(_a = attrs.onclick) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
|
|
@@ -31,7 +33,9 @@ exports.MenuButton = {
|
|
|
31
33
|
(0, mithril_1.default)("button", {
|
|
32
34
|
class: `mico-menu-button ${(_c = attrs.class) !== null && _c !== void 0 ? _c : ""} ${menu_settings_1.MENU_SETTINGS.MENU_BUTTON_CLASS}`,
|
|
33
35
|
style: `${(_d = attrs.style) !== null && _d !== void 0 ? _d : ""} width: 100%; height: 1.5rem; padding-right: 0.5rem; display: flex; align-items: center;`,
|
|
36
|
+
role: "menuitem",
|
|
34
37
|
disabled: attrs.disabled,
|
|
38
|
+
"aria-disabled": attrs.disabled ? "true" : undefined,
|
|
35
39
|
onclick: (ev) => {
|
|
36
40
|
var _a;
|
|
37
41
|
(_a = attrs.onclick) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
|
|
@@ -12,6 +12,8 @@ exports.MenuSeparator = {
|
|
|
12
12
|
return (0, mithril_1.default)("", {
|
|
13
13
|
class: `mico-menu-separator ${menu_settings_1.MENU_SETTINGS.MENU_SEPARATOR_CLASS}`,
|
|
14
14
|
style: "margin: 0.25rem 0; border-bottom-width: 1px; border-bottom-style: solid;",
|
|
15
|
+
role: "separator",
|
|
16
|
+
"aria-orientation": "horizontal",
|
|
15
17
|
});
|
|
16
18
|
}
|
|
17
19
|
};
|
|
@@ -29,8 +29,18 @@ class MenuManager {
|
|
|
29
29
|
this.containerEl = document.createElement("div");
|
|
30
30
|
this.containerEl.classList.add("menu-container");
|
|
31
31
|
document.body.append(this.containerEl);
|
|
32
|
-
document.addEventListener("click", () => {
|
|
32
|
+
document.addEventListener("click", (ev) => {
|
|
33
|
+
var _a;
|
|
33
34
|
if (this.isOpen) {
|
|
35
|
+
// If keepOpenOnClick is enabled, check if the click is within the menu
|
|
36
|
+
if ((_a = this.currentOptions) === null || _a === void 0 ? void 0 : _a.keepOpenOnClick) {
|
|
37
|
+
const target = ev.target;
|
|
38
|
+
const clickedInMenu = target.closest(".mico-menu");
|
|
39
|
+
if (clickedInMenu) {
|
|
40
|
+
menu_settings_1.MENU_SETTINGS.DEBUG_MENU && console.log("Click within menu, keeping open (keepOpenOnClick=true)");
|
|
41
|
+
return; // Don't close the menu
|
|
42
|
+
}
|
|
43
|
+
}
|
|
34
44
|
this.hide();
|
|
35
45
|
}
|
|
36
46
|
});
|
|
@@ -106,6 +116,7 @@ class MenuManager {
|
|
|
106
116
|
menuContents,
|
|
107
117
|
]);
|
|
108
118
|
this._menuVnode.next(menuVnode);
|
|
119
|
+
this.currentOptions = options;
|
|
109
120
|
// If the menu is to be shown as a dialog, we need to mount it to a dialog element
|
|
110
121
|
if (options === null || options === void 0 ? void 0 : options.asDialog) {
|
|
111
122
|
// this.dialogEl = document.createElement("dialog");
|
|
@@ -158,6 +169,7 @@ class MenuManager {
|
|
|
158
169
|
this.directParentEl = undefined;
|
|
159
170
|
(_b = this.dialogEl) === null || _b === void 0 ? void 0 : _b.close();
|
|
160
171
|
mithril_1.default.render(this.dialogEl, []);
|
|
172
|
+
this.currentOptions = undefined;
|
|
161
173
|
menu_settings_1.MENU_SETTINGS.DEBUG_MENU && console.log("Closed menu");
|
|
162
174
|
}
|
|
163
175
|
/**
|
|
@@ -35,7 +35,7 @@ export interface TableState<T> {
|
|
|
35
35
|
/** Helper function to make it easier to define table columns */
|
|
36
36
|
export type TableColumnDefinitionFn<T> = (
|
|
37
37
|
/** The label or other element to display in the header */
|
|
38
|
-
header:
|
|
38
|
+
header: m.Children,
|
|
39
39
|
/** Function defining how to display a cell in the column using the given row item */
|
|
40
40
|
cell: TableCellDisplayFn<T>,
|
|
41
41
|
/** Optional settings to tweak the column's behaviour */
|