@hypericon/mico 0.3.8 → 0.3.10

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.
Files changed (37) hide show
  1. package/dist/components/index.d.ts +1 -0
  2. package/dist/components/index.js +1 -1
  3. package/dist/components/markdown-editor/MarkdownEditor.d.ts +2 -0
  4. package/dist/components/markdown-editor/MarkdownEditor.js +5 -0
  5. package/dist/components/pagination/Pagination.d.ts +40 -0
  6. package/dist/components/pagination/Pagination.js +72 -0
  7. package/dist/components/pagination/index.d.ts +2 -0
  8. package/dist/components/pagination/index.js +17 -0
  9. package/dist/components/pagination/pagination-settings.d.ts +17 -0
  10. package/dist/components/pagination/pagination-settings.js +19 -0
  11. package/dist/components/panel-tree/PanelTree.d.ts +26 -0
  12. package/dist/components/panel-tree/PanelTree.js +180 -0
  13. package/dist/components/panel-tree/index.d.ts +0 -0
  14. package/dist/components/panel-tree/index.js +1 -0
  15. package/dist/components/panel-tree/panel-tree-constants.d.ts +3 -0
  16. package/dist/components/panel-tree/panel-tree-constants.js +6 -0
  17. package/dist/components/panel-tree/panel-tree-store.d.ts +23 -0
  18. package/dist/components/panel-tree/panel-tree-store.js +63 -0
  19. package/dist/components/panel-tree/panel-tree-utils.d.ts +17 -0
  20. package/dist/components/panel-tree/panel-tree-utils.js +59 -0
  21. package/dist/components/reorderable-list/RedorderableList.d.ts +55 -0
  22. package/dist/components/reorderable-list/RedorderableList.js +208 -0
  23. package/dist/components/tab-panel/TabPanel.d.ts +23 -0
  24. package/dist/components/tab-panel/TabPanel.js +94 -0
  25. package/dist/components/tab-panel/index.d.ts +3 -0
  26. package/dist/components/tab-panel/index.js +19 -0
  27. package/dist/components/tab-panel/tab-panel-default-settings.d.ts +17 -0
  28. package/dist/components/tab-panel/tab-panel-default-settings.js +20 -0
  29. package/dist/components/tab-panel/tab-panel-settings.d.ts +28 -0
  30. package/dist/components/tab-panel/tab-panel-settings.js +12 -0
  31. package/dist/utils/dom.d.ts +16 -0
  32. package/dist/utils/dom.js +33 -0
  33. package/dist/utils/events.d.ts +0 -7
  34. package/dist/utils/events.js +1 -16
  35. package/dist/utils/index.d.ts +1 -0
  36. package/dist/utils/index.js +1 -0
  37. package/package.json +3 -1
@@ -4,4 +4,5 @@ export * from "./icon";
4
4
  export * from "./markdown";
5
5
  export * from "./markdown-editor";
6
6
  export * from "./menu";
7
+ export * from "./pagination";
7
8
  export * from "./table";
@@ -26,7 +26,7 @@ __exportStar(require("./markdown"), exports);
26
26
  __exportStar(require("./markdown-editor"), exports);
27
27
  __exportStar(require("./menu"), exports);
28
28
  // export * from "./modal";
29
- // export * from "./pagination";
29
+ __exportStar(require("./pagination"), exports);
30
30
  // export * from "./popover";
31
31
  // export * from "./reorderable-list";
32
32
  __exportStar(require("./table"), exports);
@@ -12,6 +12,8 @@ export declare const MarkdownEditor: m.Component<{
12
12
  highlight?: boolean;
13
13
  /** @default true */
14
14
  enableShortcuts?: boolean;
15
+ /** Function called on licking the help button. The button is hidden if the function is undefined. */
16
+ onHelp?: () => any;
15
17
  class?: string;
16
18
  style?: string;
17
19
  }, {
@@ -133,6 +133,11 @@ exports.MarkdownEditor = {
133
133
  onclick: () => this.state.applyLink(),
134
134
  }, (0, mithril_1.default)(Icon_1.Icon, { fas: "link" })),
135
135
  ]),
136
+ attrs.onHelp !== undefined ? (0, mithril_1.default)(".editor-button-group", [
137
+ (0, mithril_1.default)("button", {
138
+ onclick: () => { var _a; return (_a = attrs.onHelp) === null || _a === void 0 ? void 0 : _a.call(attrs); },
139
+ }, (0, mithril_1.default)(Icon_1.Icon, { far: "circle-question" })),
140
+ ]) : [],
136
141
  ]),
137
142
  // Editor content
138
143
  (0, mithril_1.default)("textarea.editor-textarea", {
@@ -0,0 +1,40 @@
1
+ import m from "mithril";
2
+ export type PaginationLayout = "left" | "middle" | "right";
3
+ export interface PaginationAttrs {
4
+ /** The start of the range currently being displayed */
5
+ from: number;
6
+ /** The end of the range currently being displayed */
7
+ to: number;
8
+ /** The total number of all records available for display */
9
+ of: number;
10
+ /** Optionally override the "x-y of z" message, or disable it entirely with `false` */
11
+ xToYOfZ?: string | m.Vnode<any, any> | false;
12
+ /** Called when clicking the "next" button. The button is not displayed if this function is undefined. */
13
+ next?: (ev: MouseEvent) => any;
14
+ /** Called when clicking the "prev" button. The button is not displayed if this function is undefined. */
15
+ prev?: (ev: MouseEvent) => any;
16
+ /** Called when clicking the "first" button. The button is not displayed if this function is undefined. */
17
+ first?: (ev: MouseEvent) => any;
18
+ /** Called when clicking the "last" button. The button is not displayed if this function is undefined. */
19
+ last?: (ev: MouseEvent) => any;
20
+ /** Indicate the user is at the start of the data */
21
+ isAtStart?: boolean;
22
+ /** Indicate the user is at the end of the data */
23
+ isAtEnd?: boolean;
24
+ /** Override how the pagination should float along the row */
25
+ layout?: PaginationLayout;
26
+ /** Enable display and selection of page sizes */
27
+ size?: {
28
+ /** The current size of the page */
29
+ size: number;
30
+ /** Function called when a new page size is selected */
31
+ onselect: (size: number) => any;
32
+ /** Override the default list of available sizes to choose from */
33
+ sizes?: number[];
34
+ };
35
+ /** CSS classes to apply to the row container element */
36
+ class?: string;
37
+ /** CSS styles to apply to the row container element */
38
+ style?: string;
39
+ }
40
+ export declare const Pagination: m.Component<PaginationAttrs>;
@@ -0,0 +1,72 @@
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.Pagination = void 0;
7
+ const mithril_1 = __importDefault(require("mithril"));
8
+ const pagination_settings_1 = require("./pagination-settings");
9
+ const icon_1 = require("../icon");
10
+ exports.Pagination = {
11
+ view({ attrs }) {
12
+ var _a, _b;
13
+ const layout = (attrs.layout || pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.layout);
14
+ return (0, mithril_1.default)(".mico-pagination", {
15
+ class: `${(_a = attrs.class) !== null && _a !== void 0 ? _a : ""}`,
16
+ style: `${(_b = attrs.style) !== null && _b !== void 0 ? _b : ""} display: flex; align-items: center;`,
17
+ }, [
18
+ (layout === "middle" || layout === "right") ? (0, mithril_1.default)("", { style: "flex: 1;" }) : [],
19
+ (attrs.size) ? [
20
+ (0, mithril_1.default)("span", `Page size:`),
21
+ (0, mithril_1.default)("select.mico-pagination-select", {
22
+ value: attrs.size.size,
23
+ oninput: (e) => attrs.size.onselect(Number(e.target.value)),
24
+ }, (attrs.size.sizes || pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.pageSizes).map(s => (0, mithril_1.default)("option", s))),
25
+ ] : [],
26
+ (attrs.xToYOfZ !== undefined) ? [
27
+ (attrs.xToYOfZ === false) ? [] :
28
+ (typeof attrs.xToYOfZ === "string") ? (0, mithril_1.default)("span.mico-pagination-xtoyofz", attrs.xToYOfZ) :
29
+ attrs.xToYOfZ,
30
+ ] : [
31
+ (0, mithril_1.default)("span.mico-pagination-xtoyofz", `${attrs.from}-${attrs.to} of ${attrs.of}`),
32
+ ],
33
+ (attrs.first !== undefined) ? (0, mithril_1.default)("button.mico-pagination-button", {
34
+ disabled: attrs.isAtStart,
35
+ title: "First page",
36
+ onclick: (ev) => { var _a; return (_a = attrs.first) === null || _a === void 0 ? void 0 : _a.call(attrs, ev); },
37
+ }, [
38
+ pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.first
39
+ ? (0, mithril_1.default)(pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.first)
40
+ : (0, mithril_1.default)(icon_1.Icon, { fas: "backward-step" }),
41
+ ]) : [],
42
+ (attrs.prev !== undefined) ? (0, mithril_1.default)("button.mico-pagination-button", {
43
+ disabled: attrs.isAtStart,
44
+ title: "Previous page",
45
+ onclick: (ev) => { var _a; return (_a = attrs.prev) === null || _a === void 0 ? void 0 : _a.call(attrs, ev); },
46
+ }, [
47
+ pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.prev
48
+ ? (0, mithril_1.default)(pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.prev)
49
+ : (0, mithril_1.default)(icon_1.Icon, { fas: "angle-left" }),
50
+ ]) : [],
51
+ (attrs.next !== undefined) ? (0, mithril_1.default)("button.mico-pagination-button", {
52
+ disabled: attrs.isAtEnd,
53
+ title: "Next page",
54
+ onclick: (ev) => { var _a; return (_a = attrs.next) === null || _a === void 0 ? void 0 : _a.call(attrs, ev); },
55
+ }, [
56
+ pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.next
57
+ ? (0, mithril_1.default)(pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.next)
58
+ : (0, mithril_1.default)(icon_1.Icon, { fas: "angle-right" }),
59
+ ]) : [],
60
+ (attrs.last !== undefined) ? (0, mithril_1.default)("button.mico-pagination-button", {
61
+ disabled: attrs.isAtEnd,
62
+ title: "Last page",
63
+ onclick: (ev) => { var _a; return (_a = attrs.last) === null || _a === void 0 ? void 0 : _a.call(attrs, ev); },
64
+ }, [
65
+ pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.last
66
+ ? (0, mithril_1.default)(pagination_settings_1.PAGINATION_DEFAULT_SETTINGS.iconComponents.last)
67
+ : (0, mithril_1.default)(icon_1.Icon, { fas: "forward-step" }),
68
+ ]) : [],
69
+ (layout === "middle" || layout === "left") ? (0, mithril_1.default)("", { style: "flex: 1;" }) : [],
70
+ ]);
71
+ },
72
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./Pagination";
2
+ export * from "./pagination-settings";
@@ -1 +1,18 @@
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("./Pagination"), exports);
18
+ __exportStar(require("./pagination-settings"), exports);
@@ -0,0 +1,17 @@
1
+ import m from "mithril";
2
+ /**
3
+ * Default common settings for pagination components
4
+ */
5
+ export declare const PAGINATION_DEFAULT_SETTINGS: {
6
+ /** "left" | "middle" | "right" */
7
+ layout: string;
8
+ pageSize: number;
9
+ pageSizes: number[];
10
+ /** Optionally override the default icon components displayed in the pagination buttons */
11
+ iconComponents: {
12
+ first: m.Component<any, any> | undefined;
13
+ prev: m.Component<any, any> | undefined;
14
+ next: m.Component<any, any> | undefined;
15
+ last: m.Component<any, any> | undefined;
16
+ };
17
+ };
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PAGINATION_DEFAULT_SETTINGS = void 0;
4
+ /**
5
+ * Default common settings for pagination components
6
+ */
7
+ exports.PAGINATION_DEFAULT_SETTINGS = {
8
+ /** "left" | "middle" | "right" */
9
+ layout: "right",
10
+ pageSize: 25,
11
+ pageSizes: [25, 50, 100],
12
+ /** Optionally override the default icon components displayed in the pagination buttons */
13
+ iconComponents: {
14
+ first: undefined,
15
+ prev: undefined,
16
+ next: undefined,
17
+ last: undefined,
18
+ },
19
+ };
@@ -0,0 +1,26 @@
1
+ import m from "mithril";
2
+ export declare const PanelTreePanel: m.Component<{
3
+ /** The data subtree associated with this panel */
4
+ data: object;
5
+ /** The type of parent container (if any) to inform how the dragging target is highlighted (or not) */
6
+ parentType: "row" | "column" | undefined;
7
+ /** Remove the data associated with this panel from the canonical tree to be inserted elsewhere */
8
+ remove: () => void;
9
+ /** Insert the given subtree either before or after the current node as a sibling in the tree */
10
+ insert: (subtree: object, before: boolean) => void;
11
+ debugLabel?: string;
12
+ class?: string;
13
+ style?: string;
14
+ }, {
15
+ /** Whether the current drag is over the "start" or "end" of the panel, according to the parent direction */
16
+ isOverStart: boolean;
17
+ el: HTMLElement;
18
+ }>;
19
+ export declare const PanelTreeHandle: m.Component<{
20
+ /** The data subtree associated with this panel */
21
+ data: object;
22
+ /** Remove the data associated with this panel from the canonical tree to be inserted elsewhere */
23
+ remove: () => void;
24
+ }, {
25
+ el: HTMLElement;
26
+ }>;
@@ -0,0 +1,180 @@
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.PanelTreeHandle = exports.PanelTreePanel = void 0;
7
+ const mithril_1 = __importDefault(require("mithril"));
8
+ const panel_tree_constants_1 = require("./panel-tree-constants");
9
+ const panel_tree_store_1 = require("./panel-tree-store");
10
+ const panel_tree_utils_1 = require("./panel-tree-utils");
11
+ /** Data about the state of the ongoing drag operation */
12
+ const PTStore = new panel_tree_store_1.PanelTreeStore();
13
+ exports.PanelTreePanel = {
14
+ oninit() {
15
+ // this.isDragOver = false;
16
+ },
17
+ oncreate({ dom }) {
18
+ this.el = dom;
19
+ },
20
+ onupdate({ dom }) {
21
+ this.el = dom;
22
+ },
23
+ view({ attrs, children }) {
24
+ var _a, _b, _c;
25
+ const { parentType, data } = attrs;
26
+ const isOver = PTStore.isDragging && PTStore.overEl === this.el;
27
+ const isRecursive = (_a = PTStore.draggedPanel) === null || _a === void 0 ? void 0 : _a.contains(this.el);
28
+ const isValidTarget = (parentType !== undefined) && (PTStore.draggedData !== data) && !isRecursive;
29
+ let dragBorder = "border border-grey-300 dark:border-grey-700";
30
+ if (isOver && isValidTarget) {
31
+ if (parentType === "row" && this.isOverStart) {
32
+ dragBorder = "border-primary border-l-4";
33
+ }
34
+ else if (parentType === "row" && !this.isOverStart) {
35
+ dragBorder = "border-primary border-r-4";
36
+ }
37
+ else if (parentType === "column" && this.isOverStart) {
38
+ dragBorder = "border-primary border-t-4";
39
+ }
40
+ else if (parentType === "column" && !this.isOverStart) {
41
+ dragBorder = "border-primary border-b-4";
42
+ }
43
+ }
44
+ if (isOver && !isValidTarget) {
45
+ dragBorder = "border-grey-500 border";
46
+ }
47
+ const onOver = (ev) => {
48
+ var _a;
49
+ if (!PTStore.isDragging)
50
+ return;
51
+ ev.stopImmediatePropagation();
52
+ ev.preventDefault();
53
+ // PANEL_TREE_DEBUG ?? console.debug("is dragging over panel with parent " + parentType);
54
+ const { dragEv, touchEv } = panel_tree_utils_1.PanelTreeUtils.dragOrTouch(ev);
55
+ PTStore.overEl = this.el;
56
+ const isRecursive = (_a = PTStore.draggedPanel) === null || _a === void 0 ? void 0 : _a.contains(this.el);
57
+ const isValidTarget = parentType !== undefined && PTStore.draggedData !== data && !isRecursive;
58
+ if (isValidTarget) {
59
+ // this.isDragOver = true;
60
+ PTStore.dropEffect = (parentType === undefined) ? "none" : "move";
61
+ if (dragEv === null || dragEv === void 0 ? void 0 : dragEv.dataTransfer) {
62
+ dragEv.dataTransfer.dropEffect = PTStore.dropEffect;
63
+ }
64
+ // Determine if the drag is over the "starting end" of the panel
65
+ const overDiv = ev.currentTarget;
66
+ const targetRect = overDiv.getBoundingClientRect();
67
+ if (parentType === "row") {
68
+ const leftToMouse = panel_tree_utils_1.PanelTreeUtils.eventXPos(ev) - targetRect.left;
69
+ const isLeft = leftToMouse < (targetRect.width - leftToMouse);
70
+ this.isOverStart = isLeft;
71
+ }
72
+ else {
73
+ const topToMouse = panel_tree_utils_1.PanelTreeUtils.eventYPos(ev) - targetRect.top;
74
+ const isAbove = topToMouse < (targetRect.height - topToMouse);
75
+ this.isOverStart = isAbove;
76
+ }
77
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`dragging over valid target, ${this.isOverStart ? "over start" : "over end"}`);
78
+ }
79
+ else {
80
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`dragging over invalid target`);
81
+ }
82
+ };
83
+ const onDrop = (ev) => {
84
+ var _a;
85
+ if (!PTStore.isDragging)
86
+ return;
87
+ ev.stopImmediatePropagation();
88
+ // this.isDragOver = false;
89
+ PTStore.dropTargetData = data;
90
+ PTStore.dropTargetPanel = this.el;
91
+ const isRecursive = (_a = PTStore.draggedPanel) === null || _a === void 0 ? void 0 : _a.contains(this.el);
92
+ const movedData = PTStore.draggedData;
93
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`drag dropped, dataTransfer data: ${JSON.stringify(movedData)}`);
94
+ if (movedData && movedData !== data && !isRecursive) {
95
+ setTimeout(() => {
96
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`Instruct tree to insert subtree: ${JSON.stringify(movedData)}`);
97
+ attrs.insert(movedData, this.isOverStart);
98
+ mithril_1.default.redraw();
99
+ }, 1);
100
+ }
101
+ PTStore.isDragging = false;
102
+ };
103
+ const onEnd = (ev) => {
104
+ // ev.stopImmediatePropagation();
105
+ // this.isDragOver = false;
106
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug("drag ended");
107
+ // No op?
108
+ PTStore.isDragging = false;
109
+ };
110
+ return (0, mithril_1.default)(`.${panel_tree_constants_1.PANEL_TREE_PANEL_CLASS}.flex-1.rounded.shadow-md`, {
111
+ // TODO
112
+ // class: `${attrs.class ?? ""} ${mobileMode.isMob ? "p-1" : "p-2"} ${dragBorder}`,
113
+ class: `${(_b = attrs.class) !== null && _b !== void 0 ? _b : ""} p-1 ${dragBorder}`,
114
+ style: (_c = attrs.style) !== null && _c !== void 0 ? _c : "",
115
+ ondragover: (ev) => {
116
+ return onOver(ev);
117
+ },
118
+ ondragleave: (ev) => {
119
+ // ev.stopImmediatePropagation();
120
+ // if (ev.currentTarget === this.el) {
121
+ // PANEL_TREE_DEBUG ?? console.debug("drag leave target", ev.target);
122
+ // PANEL_TREE_DEBUG ?? console.debug("drag leave current target", ev.currentTarget);
123
+ // // PANEL_TREE_DEBUG ?? console.debug(`Leaving panel ${attrs.debugLabel}`);
124
+ // // this.isDragOver = false;
125
+ // }
126
+ },
127
+ ondrop: (ev) => {
128
+ return onDrop(ev);
129
+ },
130
+ ondragend: (ev) => {
131
+ return onEnd(ev);
132
+ },
133
+ // Event redispatched from the drag handle
134
+ ontouchmove: (ev) => {
135
+ return onOver(ev);
136
+ },
137
+ // Event redispatched from the drag handle
138
+ ontouchend: (ev) => {
139
+ return onDrop(ev);
140
+ },
141
+ }, children);
142
+ },
143
+ };
144
+ exports.PanelTreeHandle = {
145
+ oninit() { },
146
+ oncreate({ dom }) {
147
+ this.el = dom;
148
+ },
149
+ view({ attrs }) {
150
+ const { data } = attrs;
151
+ return (0, mithril_1.default)(".px-2.py-1.flex.items-center.cursor-move", {
152
+ // TODO
153
+ // ...tooltipSpread("Reposition this element", { delay: 1_000 }),
154
+ draggable: true,
155
+ ondragstart: (ev) => PTStore.onStartDraggingHandle(ev, data),
156
+ ondragend: (ev) => PTStore.onEndDraggingHandle(ev, data, () => { var _a; return (_a = attrs.remove) === null || _a === void 0 ? void 0 : _a.call(attrs); }),
157
+ ontouchstart: (ev) => PTStore.onStartDraggingHandle(ev, data),
158
+ // Redispatch the event to the panel that the touch is currently over
159
+ ontouchmove: (ev) => {
160
+ if (PTStore.isDragging) {
161
+ // Disable scrolling if there is an ongoing drag
162
+ ev.stopImmediatePropagation();
163
+ ev.preventDefault();
164
+ panel_tree_utils_1.PanelTreeUtils.dispatchTouchEventToHoveredPanel(ev);
165
+ }
166
+ },
167
+ ontouchend: (ev) => {
168
+ // Re-dispatch the event first to set the drop target data
169
+ panel_tree_utils_1.PanelTreeUtils.dispatchTouchEventToLastHoveredPanel(ev);
170
+ // Next, handle the end of the drag and possibly call the function to remove the panel
171
+ PTStore.onEndDraggingHandle(ev, data, () => { var _a; return (_a = attrs.remove) === null || _a === void 0 ? void 0 : _a.call(attrs); });
172
+ },
173
+ ontouchcancel: (ev) => {
174
+ PTStore.isDragging = false;
175
+ },
176
+ }, [
177
+ (0, mithril_1.default)("i.fas.fa-grip-vertical.text-icon"),
178
+ ]);
179
+ },
180
+ };
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,3 @@
1
+ /** The CSS class applied all panel tree panels */
2
+ export declare const PANEL_TREE_PANEL_CLASS = "panel-tree-panel";
3
+ export declare const PANEL_TREE_DEBUG = false;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PANEL_TREE_DEBUG = exports.PANEL_TREE_PANEL_CLASS = void 0;
4
+ /** The CSS class applied all panel tree panels */
5
+ exports.PANEL_TREE_PANEL_CLASS = "panel-tree-panel";
6
+ exports.PANEL_TREE_DEBUG = false;
@@ -0,0 +1,23 @@
1
+ export declare class PanelTreeStore {
2
+ /** If there is an ongoing drag operation */
3
+ isDragging: boolean;
4
+ /** The panel in the tree being moved by an ongoing drag operation */
5
+ draggedPanel: HTMLElement | undefined;
6
+ /** The panel in the tree that has just had a drag event dropped onto it */
7
+ dropTargetPanel: HTMLElement | undefined;
8
+ /** The panel over which the ongoing drag was last dragged */
9
+ overEl: HTMLElement | undefined;
10
+ /** The data being "moved" by the drag operation */
11
+ draggedData: object | undefined;
12
+ /** The data associated with the target for the drop action */
13
+ dropTargetData: object | undefined;
14
+ /** Mirrored from `dragEvent.dataTransfer.dropEffect` to support touch drags */
15
+ dropEffect: "none" | "copy" | "link" | "move" | undefined;
16
+ /** Whether the current drop operation is recursive */
17
+ get isRecursive(): boolean;
18
+ constructor();
19
+ /** The user has started dragging a handle of a panel */
20
+ onStartDraggingHandle(ev: DragEvent | TouchEvent, data: object): void;
21
+ /** The user has stopped dragging a handle of a panel */
22
+ onEndDraggingHandle(ev: DragEvent | TouchEvent, data: object, remove: () => void): void;
23
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PanelTreeStore = void 0;
4
+ const panel_tree_constants_1 = require("./panel-tree-constants");
5
+ const panel_tree_utils_1 = require("./panel-tree-utils");
6
+ class PanelTreeStore {
7
+ /** Whether the current drop operation is recursive */
8
+ get isRecursive() {
9
+ return (this.draggedPanel !== undefined) &&
10
+ (this.dropTargetPanel !== undefined) &&
11
+ (this.draggedPanel.contains(this.dropTargetPanel));
12
+ }
13
+ constructor() {
14
+ /** If there is an ongoing drag operation */
15
+ this.isDragging = false;
16
+ /** The panel in the tree being moved by an ongoing drag operation */
17
+ this.draggedPanel = undefined;
18
+ /** The panel in the tree that has just had a drag event dropped onto it */
19
+ this.dropTargetPanel = undefined;
20
+ /** The panel over which the ongoing drag was last dragged */
21
+ this.overEl = undefined;
22
+ /** The data being "moved" by the drag operation */
23
+ this.draggedData = undefined;
24
+ /** The data associated with the target for the drop action */
25
+ this.dropTargetData = undefined;
26
+ /** Mirrored from `dragEvent.dataTransfer.dropEffect` to support touch drags */
27
+ this.dropEffect = undefined;
28
+ }
29
+ /** The user has started dragging a handle of a panel */
30
+ onStartDraggingHandle(ev, data) {
31
+ var _a;
32
+ ev.stopImmediatePropagation();
33
+ // ev.preventDefault();
34
+ const { dragEv, touchEv } = panel_tree_utils_1.PanelTreeUtils.dragOrTouch(ev);
35
+ const parentPanel = panel_tree_utils_1.PanelTreeUtils.findParentPanel(ev.currentTarget);
36
+ // logger.debug(``)
37
+ if (parentPanel) {
38
+ this.isDragging = true;
39
+ this.draggedData = data;
40
+ this.draggedPanel = parentPanel;
41
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`Begin dragging, handle data: ${JSON.stringify(data)}`);
42
+ const parentRect = parentPanel.getBoundingClientRect();
43
+ if (dragEv) {
44
+ (_a = dragEv.dataTransfer) === null || _a === void 0 ? void 0 : _a.setDragImage(parentPanel, dragEv.clientX - parentRect.left, dragEv.clientY - parentRect.top);
45
+ }
46
+ }
47
+ }
48
+ /** The user has stopped dragging a handle of a panel */
49
+ onEndDraggingHandle(ev, data, remove) {
50
+ ev.stopImmediatePropagation();
51
+ const { dragEv, touchEv } = panel_tree_utils_1.PanelTreeUtils.dragOrTouch(ev);
52
+ const isRecursive = this.isRecursive; // STORE.dropTargetPanel && STORE.draggedPanel?.contains(STORE.dropTargetPanel);
53
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`End dragging, dropEffect: ${this.dropEffect}, handle data: ${JSON.stringify(data)}`);
54
+ if (this.dropEffect === "move") {
55
+ if (this.dropTargetData !== data && !isRecursive) {
56
+ panel_tree_constants_1.PANEL_TREE_DEBUG !== null && panel_tree_constants_1.PANEL_TREE_DEBUG !== void 0 ? panel_tree_constants_1.PANEL_TREE_DEBUG : console.debug(`Instruct tree to remove subtree: ${JSON.stringify(data)}`);
57
+ remove === null || remove === void 0 ? void 0 : remove();
58
+ }
59
+ }
60
+ this.isDragging = false;
61
+ }
62
+ }
63
+ exports.PanelTreeStore = PanelTreeStore;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Stateless utility functions used by the PanelTree component
3
+ */
4
+ export declare class PanelTreeUtils {
5
+ /** The last panel that was targetted when re-dispatching a touch event */
6
+ static lastTouchHoverPanel: HTMLElement | undefined;
7
+ /** Find the first parent element of the given element that contains the CSS class for panel tree panels */
8
+ static findParentPanel(handleEl: HTMLElement): HTMLElement | undefined;
9
+ static dragOrTouch(ev: DragEvent | TouchEvent): {
10
+ dragEv: DragEvent | undefined;
11
+ touchEv: TouchEvent | undefined;
12
+ };
13
+ static eventXPos(ev: DragEvent | TouchEvent): number;
14
+ static eventYPos(ev: DragEvent | TouchEvent): number;
15
+ static dispatchTouchEventToHoveredPanel(ev: TouchEvent): void;
16
+ static dispatchTouchEventToLastHoveredPanel(ev: TouchEvent): void;
17
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PanelTreeUtils = void 0;
4
+ const panel_tree_constants_1 = require("./panel-tree-constants");
5
+ /**
6
+ * Stateless utility functions used by the PanelTree component
7
+ */
8
+ class PanelTreeUtils {
9
+ /** Find the first parent element of the given element that contains the CSS class for panel tree panels */
10
+ static findParentPanel(handleEl) {
11
+ const parent = handleEl.parentElement;
12
+ if (!parent)
13
+ return;
14
+ if (parent.classList.contains(panel_tree_constants_1.PANEL_TREE_PANEL_CLASS))
15
+ return parent;
16
+ return this.findParentPanel(parent);
17
+ }
18
+ static dragOrTouch(ev) {
19
+ const dragEv = ev.type.includes("drag") ? ev : undefined;
20
+ const touchEv = (ev.type.includes("touch")) ? ev : undefined;
21
+ return {
22
+ dragEv,
23
+ touchEv,
24
+ };
25
+ }
26
+ static eventXPos(ev) {
27
+ if (ev.type.includes("touch")) {
28
+ return ev.touches[0].clientX;
29
+ }
30
+ else {
31
+ return ev.clientX;
32
+ }
33
+ }
34
+ static eventYPos(ev) {
35
+ if (ev.type.includes("touch")) {
36
+ return ev.touches[0].clientY;
37
+ }
38
+ else {
39
+ return ev.clientY;
40
+ }
41
+ }
42
+ static dispatchTouchEventToHoveredPanel(ev) {
43
+ // Find element dragged over
44
+ const overEl = document.elementFromPoint(ev.touches[0].clientX, ev.touches[0].clientY);
45
+ const panel = overEl ? this.findParentPanel(overEl) : undefined;
46
+ if (panel) {
47
+ this.lastTouchHoverPanel = panel;
48
+ const evCopy = new TouchEvent(ev.type, ev);
49
+ panel.dispatchEvent(evCopy);
50
+ }
51
+ }
52
+ static dispatchTouchEventToLastHoveredPanel(ev) {
53
+ if (this.lastTouchHoverPanel) {
54
+ const evCopy = new TouchEvent(ev.type, ev);
55
+ this.lastTouchHoverPanel.dispatchEvent(evCopy);
56
+ }
57
+ }
58
+ }
59
+ exports.PanelTreeUtils = PanelTreeUtils;
@@ -0,0 +1,55 @@
1
+ import m from "mithril";
2
+ /**
3
+ * A reorderable list of items. Expects a list of reorderable list items in children.
4
+ *
5
+ * ! The divs containing the content of the items must be passed as a 1-D list to
6
+ * the reorderable list's children. E.g.:
7
+ *
8
+ * ```ts
9
+ * m(ReorderableList, {...}, ["one", "two"]),
10
+ * ```
11
+ *
12
+ * Or (note the list spread):
13
+ *
14
+ * ```ts
15
+ * m(ReorderableList, {...}, [
16
+ * ...someList.map(item => m("", {...}, [...])),
17
+ * ]),
18
+ * ```
19
+ *
20
+ * The divs defining the content of the items are displayed in a flex row, and are encouraged
21
+ * to flex themselves to fill the row.
22
+ *
23
+ * Example of applying a reordering:
24
+ *
25
+ * ```ts
26
+ * const dragged = this.items.splice(fromIndex, 1)[0];
27
+ * this.items.splice(toIndex, 0, dragged);
28
+ * ```
29
+ */
30
+ export declare const ReorderableList: m.Component<{
31
+ /** A reorder instruction from the user */
32
+ reorder: (fromIndex: number, toIndex: number) => any;
33
+ /** Function called when a reordering drag begins */
34
+ reorderStart?: (ev: MouseEvent | TouchEvent) => any;
35
+ /** Function called after a reordering drag has finished */
36
+ reorderEnd?: (ev: MouseEvent | TouchEvent) => any;
37
+ /** Message to display when there are no items in the list */
38
+ emptyMessage?: string | m.Vnode<any, any>;
39
+ /** Disable reordering and the UI prompts */
40
+ disableReordering?: boolean;
41
+ /** Optionally hide the row numbers and narrow the reorder grip area */
42
+ hideNumbers?: boolean;
43
+ /** Optional space-separated CSS classes to apply to the container div */
44
+ class?: string;
45
+ /** Optional space-separated CSS classes to apply to each reorderable item row div */
46
+ itemClass?: string;
47
+ /** Optional CSS styles to apply to the container div */
48
+ style?: string;
49
+ /** Optional HTML ID for the div containing the list rows */
50
+ id?: string;
51
+ }, {
52
+ draggingIndex: number | undefined;
53
+ draggedOverIndex: number | undefined;
54
+ draggedOverTop: boolean | undefined;
55
+ }>;
@@ -0,0 +1,208 @@
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.ReorderableList = void 0;
7
+ const mithril_1 = __importDefault(require("mithril"));
8
+ const utils_1 = require("../../utils");
9
+ /**
10
+ * A reorderable list of items. Expects a list of reorderable list items in children.
11
+ *
12
+ * ! The divs containing the content of the items must be passed as a 1-D list to
13
+ * the reorderable list's children. E.g.:
14
+ *
15
+ * ```ts
16
+ * m(ReorderableList, {...}, ["one", "two"]),
17
+ * ```
18
+ *
19
+ * Or (note the list spread):
20
+ *
21
+ * ```ts
22
+ * m(ReorderableList, {...}, [
23
+ * ...someList.map(item => m("", {...}, [...])),
24
+ * ]),
25
+ * ```
26
+ *
27
+ * The divs defining the content of the items are displayed in a flex row, and are encouraged
28
+ * to flex themselves to fill the row.
29
+ *
30
+ * Example of applying a reordering:
31
+ *
32
+ * ```ts
33
+ * const dragged = this.items.splice(fromIndex, 1)[0];
34
+ * this.items.splice(toIndex, 0, dragged);
35
+ * ```
36
+ */
37
+ exports.ReorderableList = {
38
+ oninit({ attrs }) {
39
+ this.draggingIndex = undefined;
40
+ this.draggedOverIndex = undefined;
41
+ this.draggedOverTop = undefined;
42
+ // this.beginDrag = (ev: MouseEvent, index: number) => {
43
+ // this.draggingIndex = index;
44
+ // };
45
+ // this.dragOver = (ev: MouseEvent, index: number) => {
46
+ // if (this.draggingIndex === undefined) return;
47
+ // this.draggedOverIndex = index;
48
+ // };
49
+ // this.endDrag = (ev: MouseEvent) => {
50
+ // const bothIndicesDefined = (this.draggingIndex !== undefined && this.draggedOverIndex !== undefined);
51
+ // const indicesDifferent = (this.draggingIndex !== this.draggedOverIndex);
52
+ // if (bothIndicesDefined && indicesDifferent) {
53
+ // attrs.reorder?.(this.draggingIndex!, this.draggedOverIndex!);
54
+ // }
55
+ // this.draggingIndex = undefined;
56
+ // this.draggedOverIndex = undefined;
57
+ // };
58
+ },
59
+ view({ attrs, children }) {
60
+ const childArr = children instanceof Array ? children : [children];
61
+ const disableReordering = attrs.disableReordering === true;
62
+ const beginDrag = (ev, index) => {
63
+ var _a;
64
+ if (disableReordering)
65
+ return;
66
+ this.draggingIndex = index;
67
+ (_a = attrs.reorderStart) === null || _a === void 0 ? void 0 : _a.call(attrs, ev);
68
+ };
69
+ const dragOver = (ev, index, isAbove) => {
70
+ if (disableReordering)
71
+ return;
72
+ if (this.draggingIndex === undefined)
73
+ return;
74
+ this.draggedOverIndex = index;
75
+ this.draggedOverTop = isAbove;
76
+ };
77
+ const endDrag = (ev) => {
78
+ var _a, _b;
79
+ if (disableReordering)
80
+ return;
81
+ const bothIndicesDefined = (this.draggingIndex !== undefined && this.draggedOverIndex !== undefined);
82
+ const indicesDifferent = (this.draggingIndex !== this.draggedOverIndex);
83
+ if (bothIndicesDefined && indicesDifferent) {
84
+ let from = this.draggingIndex;
85
+ let to = this.draggedOverIndex;
86
+ if (from < to && this.draggedOverTop === true) {
87
+ to--;
88
+ }
89
+ else if (to < from && this.draggedOverTop === false) {
90
+ to++;
91
+ }
92
+ (_a = attrs.reorder) === null || _a === void 0 ? void 0 : _a.call(attrs, from, to);
93
+ }
94
+ if (this.draggingIndex !== undefined) {
95
+ (_b = attrs.reorderEnd) === null || _b === void 0 ? void 0 : _b.call(attrs, ev);
96
+ }
97
+ this.draggingIndex = undefined;
98
+ this.draggedOverIndex = undefined;
99
+ this.draggedOverTop = undefined;
100
+ };
101
+ return (0, mithril_1.default)("", {
102
+ id: attrs.id,
103
+ class: `${attrs.class || ""} no-select`,
104
+ style: `${attrs.style || ""}`,
105
+ onmouseup: (ev) => endDrag(ev),
106
+ onmouseleave: (ev) => endDrag(ev),
107
+ ontouchmove: (ev) => {
108
+ var _a, _b;
109
+ if (disableReordering)
110
+ return;
111
+ // This div, which contains the reorderable rows
112
+ const rowContainerEl = ev.currentTarget;
113
+ const touchX = (_a = ev.touches.item(0)) === null || _a === void 0 ? void 0 : _a.clientX;
114
+ const touchY = (_b = ev.touches.item(0)) === null || _b === void 0 ? void 0 : _b.clientY;
115
+ if (!touchX || !touchY)
116
+ return;
117
+ let overIndex = undefined;
118
+ let isAbove = undefined;
119
+ for (let i = 0; i < rowContainerEl.children.length; i++) {
120
+ const childEl = rowContainerEl.children[i];
121
+ const childElBounds = childEl.getBoundingClientRect();
122
+ if ((0, utils_1.coordsWithinElement)(touchX, touchY, childEl)) {
123
+ overIndex = i;
124
+ const boundsTopToTouch = touchY - childElBounds.top;
125
+ isAbove = boundsTopToTouch < (childElBounds.height - boundsTopToTouch);
126
+ }
127
+ }
128
+ // console.log(`touch move, in ${rowContainerEl}, coords: ${touchX}, ${touchY}, over child index: ${overIndex}`);
129
+ if (overIndex !== undefined && isAbove !== undefined) {
130
+ dragOver(ev, overIndex, isAbove);
131
+ }
132
+ },
133
+ ontouchend: (ev) => {
134
+ endDrag(ev);
135
+ },
136
+ ontouchcancel: (ev) => {
137
+ endDrag(ev);
138
+ },
139
+ }, [
140
+ (childArr.length === 0) ? attrs.emptyMessage || (0, mithril_1.default)("p", "No items to display") : [],
141
+ childArr.map((item, childIndex) => {
142
+ return (0, mithril_1.default)(ReorderableListItem, {
143
+ itemIndex: childIndex,
144
+ draggedOverIndex: this.draggedOverIndex,
145
+ draggedOverTop: this.draggedOverTop,
146
+ key: item.hasOwnProperty("key") ? item.key : undefined,
147
+ class: attrs.itemClass,
148
+ disableReordering,
149
+ hideNumbers: attrs.hideNumbers,
150
+ mouseOverFn: (ev) => {
151
+ const targetRect = ev.currentTarget.getBoundingClientRect();
152
+ const rectTopToEvent = ev.clientY - targetRect.top;
153
+ const isAbove = rectTopToEvent < (targetRect.height - rectTopToEvent);
154
+ // console.log(`mouse over, index ${childIndex}, target: ${ev.target}`);
155
+ dragOver(ev, childIndex, isAbove);
156
+ },
157
+ mouseDownFn: (ev) => beginDrag(ev, childIndex),
158
+ touchStartFn: (ev) => {
159
+ // console.log(`touch start, index ${childIndex}, target: ${ev.target}`);
160
+ ev.preventDefault();
161
+ beginDrag(ev, childIndex);
162
+ },
163
+ }, [
164
+ item,
165
+ ]);
166
+ }),
167
+ ]);
168
+ }
169
+ };
170
+ /**
171
+ * An item in the reorderable list.
172
+ *
173
+ * Contains a reordering handle with the row index, then the main content of the item.
174
+ */
175
+ const ReorderableListItem = {
176
+ view({ attrs, children }) {
177
+ var _a;
178
+ const { disableReordering, hideNumbers } = attrs;
179
+ const dragBorderClass = (attrs.draggedOverIndex !== attrs.itemIndex)
180
+ ? ""
181
+ : attrs.draggedOverTop
182
+ ? "border-t-2 border-primary"
183
+ : "border-b-2 border-primary";
184
+ return (0, mithril_1.default)(".flex.flex-row.items-stretch.space-x-2", {
185
+ key: attrs.key,
186
+ class: `${(_a = attrs.class) !== null && _a !== void 0 ? _a : ""} ${dragBorderClass}`,
187
+ style: ``,
188
+ onmousemove: (ev) => attrs.mouseOverFn(ev),
189
+ }, [
190
+ // Draggable index row header
191
+ (0, mithril_1.default)(".flex.items-center.space-x-2", {
192
+ style: `width: ${hideNumbers ? "30px" : "50px"};`,
193
+ class: `${disableReordering ? "text-hint" : "cursor-move"}`,
194
+ onmousedown: (ev) => attrs.mouseDownFn(ev),
195
+ ontouchstart: (ev) => attrs.touchStartFn(ev),
196
+ }, [
197
+ (0, mithril_1.default)(`i.fas.fa-grip-vertical`, {
198
+ class: `${disableReordering ? "text-hint" : "text-grey-700 dark:text-grey-300"} ${hideNumbers ? "pl-2" : ""}`,
199
+ }),
200
+ hideNumbers
201
+ ? []
202
+ : (0, mithril_1.default)("", attrs.itemIndex + 1),
203
+ ]),
204
+ // The content in the reorderable item
205
+ children,
206
+ ]);
207
+ }
208
+ };
@@ -0,0 +1,23 @@
1
+ import m from "mithril";
2
+ import { TabPanelSettings } from "./tab-panel-settings";
3
+ export interface TabPanelAttrs {
4
+ /** Labels of the tabs, in order. Any undefined labels or children are completely ignored. */
5
+ labels: (string | m.Vnode<any> | undefined)[];
6
+ /** Optional settings to apply to the tab panel, alongside any default settings */
7
+ settings?: TabPanelSettings;
8
+ /** If present, this field is given a function that can then be used to request tab index changes */
9
+ getRequestFn?: (requestFn: (index: number) => void) => any;
10
+ }
11
+ interface TabPanelState {
12
+ /** The currently selected index */
13
+ index: number;
14
+ /** Function to set the selected index, clamping it within actual possibilities */
15
+ setIndex: (index: number) => void;
16
+ /** The total number of tabs in the panel (completely ignoring undefined children) */
17
+ tabCount: number;
18
+ }
19
+ /**
20
+ * If a child pane is undefined, it is completely ignored.
21
+ */
22
+ export declare const TabPanel: m.Component<TabPanelAttrs, TabPanelState>;
23
+ export {};
@@ -0,0 +1,94 @@
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.TabPanel = void 0;
7
+ const mithril_1 = __importDefault(require("mithril"));
8
+ const tab_panel_default_settings_1 = require("./tab-panel-default-settings");
9
+ /**
10
+ * If a child pane is undefined, it is completely ignored.
11
+ */
12
+ exports.TabPanel = {
13
+ oninit({ attrs, state, children }) {
14
+ var _a, _b, _c;
15
+ state.tabCount = countChildren(children);
16
+ state.setIndex = (index) => {
17
+ var _a, _b;
18
+ const lastIndex = state.tabCount - 1;
19
+ if (index < 0)
20
+ index = 0;
21
+ if (index > lastIndex)
22
+ index = lastIndex;
23
+ state.index = index;
24
+ if ((_a = attrs.settings) === null || _a === void 0 ? void 0 : _a.persistenceKey)
25
+ localStorage.setItem((_b = attrs.settings) === null || _b === void 0 ? void 0 : _b.persistenceKey, String(index));
26
+ };
27
+ if ((_a = attrs.settings) === null || _a === void 0 ? void 0 : _a.persistenceKey) {
28
+ const loaded = localStorage.getItem((_b = attrs.settings) === null || _b === void 0 ? void 0 : _b.persistenceKey);
29
+ state.setIndex(Number(loaded));
30
+ }
31
+ else {
32
+ state.setIndex(((_c = attrs.settings) === null || _c === void 0 ? void 0 : _c.initialIndex) || 0);
33
+ }
34
+ // If a request function has been asked for, return it
35
+ if (attrs.getRequestFn) {
36
+ attrs.getRequestFn(state.setIndex);
37
+ }
38
+ },
39
+ onremove({ attrs, state }) {
40
+ state.setIndex = () => undefined;
41
+ },
42
+ onbeforeupdate({ attrs, state, children }) {
43
+ // Ensure any children added/removed since last redraw are accounted for
44
+ if (children instanceof Array)
45
+ children = children.filter(c => c !== undefined);
46
+ state.tabCount = countChildren(children);
47
+ },
48
+ view({ attrs, state, children }) {
49
+ var _a, _b, _c, _d, _e, _f;
50
+ // Ignore undefined children and labels
51
+ if (children instanceof Array)
52
+ children = children.filter(c => c !== undefined);
53
+ const labels = attrs.labels.filter(l => l !== undefined);
54
+ return (0, mithril_1.default)("", {
55
+ class: `${tab_panel_default_settings_1.DEFAULT_TAB_PANEL_SETTINGS.class.tabPanel} ${(_b = (_a = attrs.settings) === null || _a === void 0 ? void 0 : _a.classes) === null || _b === void 0 ? void 0 : _b.tabPanel}`,
56
+ }, [
57
+ // m(Draggable, {
58
+ // // TODO: wire up to allow draggable scrolling on desktop
59
+ // ondrag: ({ x, y }) => {},
60
+ // }, [
61
+ (0, mithril_1.default)("", {
62
+ class: `${tab_panel_default_settings_1.DEFAULT_TAB_PANEL_SETTINGS.class.buttonBar} ${(_d = (_c = attrs.settings) === null || _c === void 0 ? void 0 : _c.classes) === null || _d === void 0 ? void 0 : _d.buttonBar}`,
63
+ }, indices(state.tabCount).map(index => {
64
+ var _a, _b, _c, _d, _e, _f;
65
+ return (0, mithril_1.default)("button", {
66
+ class: (tab_panel_default_settings_1.DEFAULT_TAB_PANEL_SETTINGS.class.tabButton + " " + ((_b = (_a = attrs.settings) === null || _a === void 0 ? void 0 : _a.classes) === null || _b === void 0 ? void 0 : _b.tabButton) + " " +
67
+ (state.index === index ? tab_panel_default_settings_1.DEFAULT_TAB_PANEL_SETTINGS.class.tabButtonSelected : tab_panel_default_settings_1.DEFAULT_TAB_PANEL_SETTINGS.class.tabButtonUnselected) + " " +
68
+ (state.index === index ? (_d = (_c = attrs.settings) === null || _c === void 0 ? void 0 : _c.classes) === null || _d === void 0 ? void 0 : _d.tabButtonSelected : (_f = (_e = attrs.settings) === null || _e === void 0 ? void 0 : _e.classes) === null || _f === void 0 ? void 0 : _f.tabButtonUnselected)),
69
+ onclick: () => state.setIndex(index),
70
+ }, labels[index] || `Tab ${index + 1}`);
71
+ })),
72
+ // ]),
73
+ (0, mithril_1.default)("div", {
74
+ class: `${tab_panel_default_settings_1.DEFAULT_TAB_PANEL_SETTINGS.class.selectedPane} ${(_f = (_e = attrs.settings) === null || _e === void 0 ? void 0 : _e.classes) === null || _f === void 0 ? void 0 : _f.selectedPane}`,
75
+ }, [
76
+ (!(children instanceof Array)) ? children :
77
+ children.map((child, index) => (0, mithril_1.default)("", {
78
+ style: `display: ${index === state.index ? "block" : "none"}`,
79
+ }, child)),
80
+ ]),
81
+ ]);
82
+ }
83
+ };
84
+ function countChildren(children) {
85
+ if (children === undefined)
86
+ return 0;
87
+ if (children instanceof Array)
88
+ return children.filter(c => c !== undefined).length;
89
+ return 1;
90
+ }
91
+ /** Converts a count to a list of indices */
92
+ function indices(count) {
93
+ return Array(count).fill(0).map((val, index) => index);
94
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./tab-panel-default-settings";
2
+ export * from "./tab-panel-settings";
3
+ export * from "./TabPanel";
@@ -0,0 +1,19 @@
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("./tab-panel-default-settings"), exports);
18
+ __exportStar(require("./tab-panel-settings"), exports);
19
+ __exportStar(require("./TabPanel"), exports);
@@ -0,0 +1,17 @@
1
+ export declare const DEFAULT_TAB_PANEL_SETTINGS: {
2
+ /** Optional CSS classes to apply to parts of the tab panel */
3
+ class: {
4
+ /** Space-separated CSS classes to apply to the entire tab panel */
5
+ tabPanel: string;
6
+ /** Space-separated CSS classes to apply to the panel's button bar */
7
+ buttonBar: string;
8
+ /** Space-separated CSS classes to apply to all tab buttons */
9
+ tabButton: string;
10
+ /** Space-separated CSS classes to apply to the currently-selected tab button */
11
+ tabButtonUnselected: string;
12
+ /** Space-separated CSS classes to apply to all the currently-unselected tab buttons */
13
+ tabButtonSelected: string;
14
+ /** Space-separated CSS classes to apply to the tab's contents pane displaying the selected child */
15
+ selectedPane: string;
16
+ };
17
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_TAB_PANEL_SETTINGS = void 0;
4
+ exports.DEFAULT_TAB_PANEL_SETTINGS = {
5
+ /** Optional CSS classes to apply to parts of the tab panel */
6
+ class: {
7
+ /** Space-separated CSS classes to apply to the entire tab panel */
8
+ tabPanel: "",
9
+ /** Space-separated CSS classes to apply to the panel's button bar */
10
+ buttonBar: "",
11
+ /** Space-separated CSS classes to apply to all tab buttons */
12
+ tabButton: "",
13
+ /** Space-separated CSS classes to apply to the currently-selected tab button */
14
+ tabButtonUnselected: "",
15
+ /** Space-separated CSS classes to apply to all the currently-unselected tab buttons */
16
+ tabButtonSelected: "",
17
+ /** Space-separated CSS classes to apply to the tab's contents pane displaying the selected child */
18
+ selectedPane: "",
19
+ },
20
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Settings that customise the behaviour of a tab panel
3
+ */
4
+ export interface TabPanelSettings {
5
+ /** The index of the tab initially selected, default = 0 */
6
+ initialIndex?: number;
7
+ /** How to position the tabs in the row, default = "left" (NOT IMPLEMENTED) */
8
+ align?: "left" | "right" | "center" | "justify";
9
+ /** How to handle overflowing tabs in the row (NOT IMPLEMENTED) */
10
+ overflow?: "scroll" | "wrap" | "hide";
11
+ /** Optional key to use to persist the tab panel's selected tab to local storage */
12
+ persistenceKey?: string;
13
+ /** Optional CSS classes to apply to parts of the tab panel */
14
+ classes?: {
15
+ /** Space-separated CSS classes to apply to the entire tab panel */
16
+ tabPanel?: string;
17
+ /** Space-separated CSS classes to apply to the panel's button bar */
18
+ buttonBar?: string;
19
+ /** Space-separated CSS classes to apply to all tab buttons */
20
+ tabButton?: string;
21
+ /** Space-separated CSS classes to apply to the currently-selected tab button */
22
+ tabButtonSelected?: string;
23
+ /** Space-separated CSS classes to apply to all the currently-unselected tab buttons */
24
+ tabButtonUnselected?: string;
25
+ /** Space-separated CSS classes to apply to the tab's contents pane displaying the selected child */
26
+ selectedPane?: string;
27
+ };
28
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // export const DEFAULT_TAB_PANEL_SETTINGS: TabPanelSettings = {
4
+ // classes: {
5
+ // tabPanel: "w-full my-4",
6
+ // buttonBar: "flex flex-row items-center overflow-scroll hide-scrollbar border-gray-800 border-b-2",
7
+ // tabButton: "btn border border-gray-800 outline-none focus:outline-none",
8
+ // tabButtonUnselected: "btn-dark",
9
+ // tabButtonSelected: "text-black bg-white",
10
+ // selectedPane: "",
11
+ // },
12
+ // };
@@ -0,0 +1,16 @@
1
+ /**
2
+ *
3
+ * @param x
4
+ * @param y
5
+ * @param element
6
+ * @param strict
7
+ * @returns
8
+ */
9
+ export declare function coordsWithinElement(x: number, y: number, element: Element, strict?: boolean): boolean;
10
+ /**
11
+ * Find whether a mouse event is within a given DOM element using clientX/Y and the bounding client rect
12
+ * @param ev
13
+ * @param element
14
+ * @returns
15
+ */
16
+ export declare function mouseWithinElement(ev: MouseEvent, element: Element): boolean;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mouseWithinElement = exports.coordsWithinElement = void 0;
4
+ /**
5
+ *
6
+ * @param x
7
+ * @param y
8
+ * @param element
9
+ * @param strict
10
+ * @returns
11
+ */
12
+ function coordsWithinElement(x, y, element, strict = false) {
13
+ const rect = element.getBoundingClientRect();
14
+ return strict
15
+ ? (rect.left < x && x < rect.right && rect.top < y && y < rect.bottom)
16
+ : (rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom);
17
+ }
18
+ exports.coordsWithinElement = coordsWithinElement;
19
+ /**
20
+ * Find whether a mouse event is within a given DOM element using clientX/Y and the bounding client rect
21
+ * @param ev
22
+ * @param element
23
+ * @returns
24
+ */
25
+ function mouseWithinElement(ev, element) {
26
+ const elementRect = element.getBoundingClientRect();
27
+ const isWithin = (ev.clientY >= elementRect.top) &&
28
+ (ev.clientY <= elementRect.bottom) &&
29
+ (ev.clientX >= elementRect.left) &&
30
+ (ev.clientX <= elementRect.right);
31
+ return isWithin;
32
+ }
33
+ exports.mouseWithinElement = mouseWithinElement;
@@ -1,8 +1 @@
1
1
  export declare function dragEventFiles(ev: DragEvent): File[];
2
- /**
3
- * Find whether a mouse event is within a given DOM element using clientX/Y and the bounding client rect
4
- * @param ev
5
- * @param element
6
- * @returns
7
- */
8
- export declare function mouseWithinElement(ev: MouseEvent, element: Element): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mouseWithinElement = exports.dragEventFiles = void 0;
3
+ exports.dragEventFiles = void 0;
4
4
  function dragEventFiles(ev) {
5
5
  var _a, _b, _c;
6
6
  const files = [];
@@ -27,18 +27,3 @@ function dragEventFiles(ev) {
27
27
  return files;
28
28
  }
29
29
  exports.dragEventFiles = dragEventFiles;
30
- /**
31
- * Find whether a mouse event is within a given DOM element using clientX/Y and the bounding client rect
32
- * @param ev
33
- * @param element
34
- * @returns
35
- */
36
- function mouseWithinElement(ev, element) {
37
- const elementRect = element.getBoundingClientRect();
38
- const isWithin = (ev.clientY >= elementRect.top) &&
39
- (ev.clientY <= elementRect.bottom) &&
40
- (ev.clientX >= elementRect.left) &&
41
- (ev.clientX <= elementRect.right);
42
- return isWithin;
43
- }
44
- exports.mouseWithinElement = mouseWithinElement;
@@ -1,2 +1,3 @@
1
1
  export * from "./date-time";
2
+ export * from "./dom";
2
3
  export * from "./events";
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./date-time"), exports);
18
+ __exportStar(require("./dom"), exports);
18
19
  __exportStar(require("./events"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypericon/mico",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "UI components and utilities with Mithril",
5
5
  "author": "Ed Johnson, Hypericon Ltd",
6
6
  "license": "MIT",
@@ -14,10 +14,12 @@
14
14
  "predeploy": "npm run build-docs",
15
15
  "deploy": "git push origin master:deploy",
16
16
  "publish-deploy": "npm publish && npm run deploy",
17
+ "deploy-publish": "npm run publish-deploy",
17
18
  "test": "echo \"Error: no test specified\" && exit 1"
18
19
  },
19
20
  "dependencies": {
20
21
  "@fortawesome/fontawesome-free": "^6.4.0",
22
+ "@hypericon/utils": "^0.5.5",
21
23
  "dompurify": "^3.0.3",
22
24
  "highlight.js": "^11.8.0",
23
25
  "marked": "^4.3.0",