@threadlabs/looma 0.10.0 → 0.10.1
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-toolbar/ui-editor-toolbar.html +70 -20
- package/components/ui-editor-toolbar/ui-editor-toolbar.js +24 -0
- package/dist/index.js +20 -19
- package/package.json +1 -1
- package/styles/ui-editor-toolbar.css +72 -18
- package/vanilla/UiEditorToolbar.js +11 -6
- package/vue/UiEditorToolbar.vue +90 -20
- package/vue/chunks/UiEditorToolbar.js +33 -4
- package/vue/components.css +70 -26
|
@@ -1,35 +1,86 @@
|
|
|
1
|
-
<template component="ui-editor-toolbar">
|
|
1
|
+
<template component="ui-editor-toolbar" controller="./ui-editor-toolbar.js">
|
|
2
2
|
<defs>
|
|
3
3
|
<prop name="floating" type="boolean" default="false">Shows the toolbar as a floating bar beside the selection rather than pinned to the editor.</prop>
|
|
4
|
+
<state name="overflowStart" :value="false"></state>
|
|
5
|
+
<state name="overflowEnd" :value="false"></state>
|
|
4
6
|
</defs>
|
|
5
|
-
<div role="toolbar" aria-label="Editor toolbar"><slot></slot></div>
|
|
7
|
+
<div role="toolbar" aria-label="Editor toolbar"><div class="strip" $ref="strip"><slot></slot></div></div>
|
|
6
8
|
<style>
|
|
7
9
|
:host {
|
|
10
|
+
/* The colour the edge fades blend into: whatever the toolbar is painted with. */
|
|
11
|
+
--_matte: var(--ui-editor-toolbar-surface, var(--ui-surface));
|
|
12
|
+
|
|
8
13
|
position: sticky;
|
|
9
14
|
top: 0;
|
|
10
15
|
z-index: var(--ui-editor-toolbar-z-index, 10);
|
|
11
16
|
display: flex;
|
|
12
17
|
align-items: center;
|
|
13
|
-
justify-content: flex-start;
|
|
14
|
-
gap: var(--ui-editor-toolbar-gap, 2px);
|
|
15
18
|
padding: var(--ui-editor-toolbar-padding-block, 6px) var(--ui-editor-toolbar-padding-inline, 12px);
|
|
16
19
|
min-height: var(--ui-editor-toolbar-min-height, 48px);
|
|
17
|
-
/* More controls than the column is wide is normal at a readable measure, so the row wraps.
|
|
18
|
-
Scrolling hid the tail behind an invisible scrollbar. */
|
|
19
|
-
flex-wrap: wrap;
|
|
20
|
-
row-gap: var(--ui-editor-toolbar-row-gap, var(--ui-editor-toolbar-gap, 2px));
|
|
21
20
|
background: var(--ui-editor-toolbar-surface, var(--ui-surface));
|
|
22
21
|
border-bottom: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
/* One row, always. When the controls outgrow the space, the row scrolls sideways rather than
|
|
25
|
+
wrapping into several lines, and a fade at each edge that has more to show says so. */
|
|
26
|
+
.strip {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex: 1 1 auto;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: flex-start;
|
|
31
|
+
gap: var(--ui-editor-toolbar-gap, 2px);
|
|
32
|
+
min-width: 0;
|
|
33
|
+
overflow-x: auto;
|
|
34
|
+
overflow-y: hidden;
|
|
35
|
+
overscroll-behavior-inline: contain;
|
|
36
|
+
scrollbar-width: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.strip::-webkit-scrollbar {
|
|
26
40
|
display: none;
|
|
27
41
|
}
|
|
28
42
|
|
|
29
|
-
|
|
43
|
+
.strip > :slotted(*) {
|
|
30
44
|
flex: 0 0 auto;
|
|
31
45
|
}
|
|
32
46
|
|
|
47
|
+
/* The fades are mattes laid over the strip in the toolbar's own colour, not a mask, so a floating
|
|
48
|
+
toolbar's border and shadow stay whole. Each appears only while that edge hides controls. */
|
|
49
|
+
:host::before,
|
|
50
|
+
:host::after {
|
|
51
|
+
position: absolute;
|
|
52
|
+
z-index: 1;
|
|
53
|
+
inset-block: 0;
|
|
54
|
+
inline-size: var(--ui-editor-toolbar-fade-size, 32px);
|
|
55
|
+
content: "";
|
|
56
|
+
opacity: 0;
|
|
57
|
+
pointer-events: none;
|
|
58
|
+
transition: opacity var(--ui-motion-fast, 120ms) var(--ui-motion-ease, ease);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:host::before {
|
|
62
|
+
inset-inline-start: 0;
|
|
63
|
+
background: linear-gradient(to right, var(--_matte), transparent);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:host::after {
|
|
67
|
+
inset-inline-end: 0;
|
|
68
|
+
background: linear-gradient(to left, var(--_matte), transparent);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:host:dir(rtl)::before {
|
|
72
|
+
background: linear-gradient(to left, var(--_matte), transparent);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
:host:dir(rtl)::after {
|
|
76
|
+
background: linear-gradient(to right, var(--_matte), transparent);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:host-state([overflowStart])::before,
|
|
80
|
+
:host-state([overflowEnd])::after {
|
|
81
|
+
opacity: 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
33
84
|
:slotted(.divider) {
|
|
34
85
|
width: 1px;
|
|
35
86
|
height: 20px;
|
|
@@ -39,14 +90,12 @@
|
|
|
39
90
|
}
|
|
40
91
|
|
|
41
92
|
:host-state([floating]) {
|
|
42
|
-
|
|
43
|
-
position: static;
|
|
93
|
+
position: relative;
|
|
44
94
|
top: auto;
|
|
45
95
|
width: max-content;
|
|
46
96
|
max-width: min(calc(100vw - 24px), 100%);
|
|
47
97
|
min-height: auto;
|
|
48
98
|
padding: var(--ui-editor-toolbar-floating-padding, 4px);
|
|
49
|
-
overflow-x: visible;
|
|
50
99
|
background: color-mix(in srgb, var(--ui-editor-toolbar-surface, var(--ui-surface)) 96%, transparent);
|
|
51
100
|
border: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
|
|
52
101
|
border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
|
|
@@ -68,7 +117,7 @@
|
|
|
68
117
|
}
|
|
69
118
|
|
|
70
119
|
:host-state([floating]) {
|
|
71
|
-
position:
|
|
120
|
+
position: relative;
|
|
72
121
|
inset: auto;
|
|
73
122
|
min-height: auto;
|
|
74
123
|
border: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
|
|
@@ -79,9 +128,10 @@
|
|
|
79
128
|
|
|
80
129
|
/* Inside LoomaEditor's sticky shell, the shell is the sticky surface. */
|
|
81
130
|
.looma-editor__sticky-toolbar-shell :host {
|
|
82
|
-
|
|
131
|
+
--_matte: var(--ui-editor-toolbar-surface, var(--ui-surface));
|
|
132
|
+
|
|
133
|
+
position: relative;
|
|
83
134
|
min-height: var(--ui-editor-toolbar-min-height, 48px);
|
|
84
|
-
overscroll-behavior-inline: contain;
|
|
85
135
|
background: transparent;
|
|
86
136
|
border: 0;
|
|
87
137
|
box-shadow: none;
|
|
@@ -93,10 +143,6 @@
|
|
|
93
143
|
max-width: none;
|
|
94
144
|
min-height: 100%;
|
|
95
145
|
padding: 0;
|
|
96
|
-
overflow-x: auto;
|
|
97
|
-
overflow-y: hidden;
|
|
98
|
-
overscroll-behavior-inline: contain;
|
|
99
|
-
scroll-snap-type: x mandatory;
|
|
100
146
|
background: transparent;
|
|
101
147
|
border: 0;
|
|
102
148
|
border-radius: 0;
|
|
@@ -104,6 +150,10 @@
|
|
|
104
150
|
backdrop-filter: none;
|
|
105
151
|
}
|
|
106
152
|
|
|
153
|
+
.looma-editor__mobile-toolbar-shell :host-state([floating]) .strip {
|
|
154
|
+
scroll-snap-type: x mandatory;
|
|
155
|
+
}
|
|
156
|
+
|
|
107
157
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
108
158
|
:host[hidden] {
|
|
109
159
|
display: none;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Tracks whether the toolbar's row hides controls past either edge, so the stylesheet can fade that
|
|
2
|
+
// edge and only that edge. A row that fits shows no fade at all.
|
|
3
|
+
export default function controller(host) {
|
|
4
|
+
const strip = host.refs.strip;
|
|
5
|
+
const update = () => {
|
|
6
|
+
const hidden = strip.scrollWidth - strip.clientWidth;
|
|
7
|
+
// Right-to-left rows scroll from 0 into negative values; measure from the start either way.
|
|
8
|
+
const scrolled = Math.abs(strip.scrollLeft);
|
|
9
|
+
host.state.overflowStart = hidden > 1 && scrolled > 1;
|
|
10
|
+
host.state.overflowEnd = hidden > 1 && scrolled < hidden - 1;
|
|
11
|
+
};
|
|
12
|
+
strip.addEventListener("scroll", update, { passive: true });
|
|
13
|
+
const resize = new ResizeObserver(update);
|
|
14
|
+
resize.observe(strip);
|
|
15
|
+
// Controls arriving, leaving, or changing size change the row's width without resizing the strip.
|
|
16
|
+
const content = new MutationObserver(update);
|
|
17
|
+
content.observe(strip, { childList: true, subtree: true, attributes: true });
|
|
18
|
+
update();
|
|
19
|
+
return () => {
|
|
20
|
+
strip.removeEventListener("scroll", update);
|
|
21
|
+
resize.disconnect();
|
|
22
|
+
content.disconnect();
|
|
23
|
+
};
|
|
24
|
+
}
|