@threadlabs/looma 0.26.17 → 0.26.19
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/components/ui-editor-table-overlay/ui-editor-table-overlay.html +2 -0
- package/components/ui-editor-table-overlay/ui-editor-table-overlay.js +1 -1
- package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.js +26 -3
- package/components/ui-menu/ui-menu.html +6 -0
- package/components/ui-menu-item/ui-menu-item.html +26 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-menu-item.css +25 -0
- package/styles/ui-menu.css +5 -0
- package/vanilla/UiEditorTableOverlay.js +1 -1
- package/vanilla/UiMenu.d.ts +1 -0
- package/vanilla/UiMenu.js +4 -4
- package/vanilla/UiMenuItem.d.ts +1 -0
- package/vanilla/UiMenuItem.js +77 -49
- package/vue/UiEditorTableOverlay.vue +30 -24
- package/vue/UiMenu.d.ts +9 -0
- package/vue/UiMenu.vue +25 -1
- package/vue/UiMenuItem.d.ts +13 -0
- package/vue/UiMenuItem.vue +48 -2
- package/vue/chunks/UiEditorTableOverlay.js +135 -123
- package/vue/chunks/UiMenu.js +24 -1
- package/vue/chunks/UiMenuItem.js +55 -12
- package/vue/components.css +126 -87
- package/vue/editor/index.js +3 -2
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
</state>
|
|
61
61
|
<state
|
|
62
62
|
name="hovered"
|
|
63
|
+
nullable
|
|
63
64
|
type="object"
|
|
64
65
|
>
|
|
65
66
|
<prop name="left" required type="number"></prop>
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
</state>
|
|
74
75
|
<state
|
|
75
76
|
name="active"
|
|
77
|
+
nullable
|
|
76
78
|
type="object"
|
|
77
79
|
>
|
|
78
80
|
<prop name="left" required type="number"></prop>
|
|
@@ -130,7 +130,7 @@ function connect(host) {
|
|
|
130
130
|
rowOffset: `${hovered.top + hovered.height / 2}px`,
|
|
131
131
|
columnOffset: `${hovered.left + hovered.width / 2}px`,
|
|
132
132
|
};
|
|
133
|
-
const active = host.props.geometry.value?.activeCell ?? null;
|
|
133
|
+
const active = hovered ?? host.props.geometry.value?.activeCell ?? null;
|
|
134
134
|
host.state.active = active && { ...active, menuLeft: `${active.left + active.width - 30}px`, menuTop: `${active.top + 6}px` };
|
|
135
135
|
queueMicrotask(proximity.refresh);
|
|
136
136
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { backgrounds } from "../shared/editor.js";
|
|
2
|
+
import { createAnchoredSurface } from "../shared/overlay.js";
|
|
2
3
|
|
|
3
4
|
const overflowSections = [
|
|
4
5
|
["Structure", [["add-row-before", "Add row above", "panel-top"], ["add-column-before", "Add column left", "panel-left"], ["toggle-header-row", "Header row", "rows"], ["toggle-header-column", "Header column", "columns"], ["move-row-up", "Move row up", "rows"], ["move-row-down", "Move row down", "rows"], ["move-column-left", "Move column left", "columns"], ["move-column-right", "Move column right", "columns"]]],
|
|
@@ -9,10 +10,19 @@ const overflowSections = [
|
|
|
9
10
|
// Lists the actions the table selection permits; the overflow menu opens and closes here.
|
|
10
11
|
function connect(host) {
|
|
11
12
|
const element = host.element;
|
|
13
|
+
let surface = null;
|
|
14
|
+
let surfaceMenu = null;
|
|
15
|
+
let positionFrame = null;
|
|
12
16
|
const positionMenu = () => {
|
|
17
|
+
if (!host.state.overflowOpen) return;
|
|
13
18
|
const button = element.querySelector(".more");
|
|
14
19
|
const menu = element.querySelector(".menu");
|
|
15
20
|
if (!button || !menu) return;
|
|
21
|
+
if (surfaceMenu !== menu) {
|
|
22
|
+
surface?.destroy();
|
|
23
|
+
surfaceMenu = menu;
|
|
24
|
+
surface = createAnchoredSurface(menu, { anchor: button, placement: "bottom-end", gap: 8, viewportGap: 12 });
|
|
25
|
+
}
|
|
16
26
|
const rect = button.getBoundingClientRect();
|
|
17
27
|
const viewport = window.visualViewport;
|
|
18
28
|
const top = viewport?.offsetTop ?? 0;
|
|
@@ -20,8 +30,11 @@ function connect(host) {
|
|
|
20
30
|
const above = rect.top - top - 20;
|
|
21
31
|
const below = bottom - rect.bottom - 20;
|
|
22
32
|
menu.style.maxHeight = `${Math.max(80, Math.floor(Math.max(above, below)))}px`;
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
surface.show();
|
|
34
|
+
};
|
|
35
|
+
const schedulePosition = () => {
|
|
36
|
+
if (positionFrame !== null) cancelAnimationFrame(positionFrame);
|
|
37
|
+
positionFrame = requestAnimationFrame(() => { positionFrame = null; positionMenu(); });
|
|
25
38
|
};
|
|
26
39
|
const stop = host.effect(() => {
|
|
27
40
|
const enabled = new Set(Array.isArray(host.props.actions.value) ? host.props.actions.value : []);
|
|
@@ -45,12 +58,19 @@ function connect(host) {
|
|
|
45
58
|
host.state.hasOverflow = host.state.swatches.length > 0 || host.state.sections.length > 0;
|
|
46
59
|
if (!host.props.open.value || !host.state.hasOverflow) host.state.overflowOpen = false;
|
|
47
60
|
});
|
|
61
|
+
const stopMenu = host.effect(() => {
|
|
62
|
+
if (host.state.overflowOpen) schedulePosition();
|
|
63
|
+
else {
|
|
64
|
+
surface?.destroy();
|
|
65
|
+
surface = null;
|
|
66
|
+
surfaceMenu = null;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
48
69
|
const onClick = (event) => {
|
|
49
70
|
const action = event.target.closest?.("[data-action]")?.dataset.action;
|
|
50
71
|
if (!action) return;
|
|
51
72
|
if (action === "toggle-overflow") {
|
|
52
73
|
host.state.overflowOpen = !host.state.overflowOpen;
|
|
53
|
-
if (host.state.overflowOpen) requestAnimationFrame(positionMenu);
|
|
54
74
|
return;
|
|
55
75
|
}
|
|
56
76
|
host.state.overflowOpen = false;
|
|
@@ -74,6 +94,9 @@ function connect(host) {
|
|
|
74
94
|
window.visualViewport?.addEventListener("resize", positionMenu);
|
|
75
95
|
return () => {
|
|
76
96
|
stop();
|
|
97
|
+
stopMenu();
|
|
98
|
+
surface?.destroy();
|
|
99
|
+
if (positionFrame !== null) cancelAnimationFrame(positionFrame);
|
|
77
100
|
element.removeEventListener("click", onClick);
|
|
78
101
|
document.removeEventListener("pointerdown", onOutside, true);
|
|
79
102
|
document.removeEventListener("keydown", onKeydown, true);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<defs>
|
|
3
3
|
<prop name="density" type="keyword" values="comfortable, compact" default="comfortable"
|
|
4
4
|
>Compact trades padding and type size for rows that fit more on screen.</prop>
|
|
5
|
+
<prop name="icons" type="boolean" default="false">Reserves a fixed icon column in every item, including items without an icon. Supply item icons through their icon slot.</prop>
|
|
5
6
|
<prop name="size" type="keyword" values="sm, md" default="md"
|
|
6
7
|
>sm sizes the menu to a small trigger, such as an xs or sm button: smallest text, short rows, a small check, and a narrower minimum width. md is the
|
|
7
8
|
standard size.</prop>
|
|
@@ -77,6 +78,10 @@
|
|
|
77
78
|
gap: 0;
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
:host([icons]) {
|
|
82
|
+
--_ui-default-menu-icon-display: inline-flex;
|
|
83
|
+
}
|
|
84
|
+
|
|
80
85
|
:host {
|
|
81
86
|
--_ui-menu-surface: var(--ui-menu-surface);
|
|
82
87
|
--_ui-menu-border: var(--ui-menu-border);
|
|
@@ -89,6 +94,7 @@
|
|
|
89
94
|
--_ui-default-menu-item-radius: initial;
|
|
90
95
|
--_ui-default-menu-item-min-block-size: initial;
|
|
91
96
|
--_ui-default-menu-indicator-size: initial;
|
|
97
|
+
--_ui-default-menu-icon-display: none;
|
|
92
98
|
display: flex;
|
|
93
99
|
flex-direction: column;
|
|
94
100
|
box-sizing: border-box;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<prop name="type" type="keyword" values="action, checkbox, radio" default="action"
|
|
11
11
|
>An action closes its menu; a checkbox toggles, and a radio chooses one item within its nearest Menu Group. Checkable items keep the menu open.</prop>
|
|
12
12
|
<prop name="checked" type="boolean" default="false">Initial or externally controlled checked state of a checkbox or radio item.</prop>
|
|
13
|
+
<prop name="tone" type="keyword" values="neutral, danger" default="neutral">Danger identifies a destructive action without changing its behavior.</prop>
|
|
13
14
|
<state type="boolean" name="internalChecked" value="false"></state>
|
|
14
15
|
<event name="change" type="object">
|
|
15
16
|
<prop name="checked" required type="boolean"></prop>
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
from:data-value="$value"
|
|
28
29
|
from:href="{ true: null, false: $href }[concat($disabled)]"
|
|
29
30
|
>
|
|
31
|
+
<span class="icon" aria-hidden="true"><slot name="icon"></slot></span>
|
|
30
32
|
<span class="label"><slot></slot></span>
|
|
31
33
|
<span class="shortcut" aria-hidden="true"><slot name="shortcut"></slot></span>
|
|
32
34
|
</a>
|
|
@@ -41,6 +43,7 @@
|
|
|
41
43
|
<span class="indicator" aria-hidden="true">
|
|
42
44
|
<ui-icon $if="($type = 'checkbox' or $type = 'radio') and $internalChecked" name="check"></ui-icon>
|
|
43
45
|
</span>
|
|
46
|
+
<span class="icon" aria-hidden="true"><slot name="icon"></slot></span>
|
|
44
47
|
<span class="label"><slot></slot></span>
|
|
45
48
|
<span class="shortcut" aria-hidden="true"><slot name="shortcut"></slot></span>
|
|
46
49
|
</div>
|
|
@@ -91,6 +94,29 @@
|
|
|
91
94
|
transition: background-color var(--ui-motion-fast) var(--ui-motion-ease), color var(--ui-motion-fast) var(--ui-motion-ease);
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
/* A named icon has a fixed column; an icon-enabled menu reserves it on every row. */
|
|
98
|
+
.icon {
|
|
99
|
+
display: var(--_ui-default-menu-icon-display, none);
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
flex: none;
|
|
103
|
+
inline-size: var(--ui-icon-size-sm);
|
|
104
|
+
block-size: var(--ui-icon-size-sm);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.icon:not(:empty) {
|
|
108
|
+
display: inline-flex;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.icon :slotted(svg) {
|
|
112
|
+
inline-size: 100%;
|
|
113
|
+
block-size: 100%;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
:host([tone="danger"]) {
|
|
117
|
+
color: var(--ui-danger);
|
|
118
|
+
}
|
|
119
|
+
|
|
94
120
|
.label {
|
|
95
121
|
display: flex;
|
|
96
122
|
align-items: center;
|