@threadlabs/looma 0.11.1 → 0.11.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/components/ui-input/ui-input.html +4 -4
- package/components/ui-input-group/ui-input-group.html +86 -0
- package/components/ui-list/ui-list.html +12 -0
- package/components/ui-list-item/ui-list-item.html +4 -4
- package/components/ui-tree-item/ui-tree-item.html +1 -1
- package/components/ui-tree-item/ui-tree-item.js +2 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-input-group.css +87 -0
- package/styles/ui-input.css +4 -4
- package/styles/ui-list-item.css +4 -4
- package/styles/ui-list.css +11 -0
- package/styles/ui-tree-item.css +2 -2
- package/vanilla/UiInputGroup.d.ts +14 -0
- package/vanilla/UiInputGroup.js +53 -0
- package/vanilla/UiList.d.ts +1 -0
- package/vanilla/UiList.js +3 -1
- package/vanilla/index.js +1 -0
- package/vue/UiInput.vue +7 -4
- package/vue/UiInputGroup.d.ts +22 -0
- package/vue/UiInputGroup.js +2 -0
- package/vue/UiInputGroup.vue +113 -0
- package/vue/UiList.d.ts +2 -0
- package/vue/UiList.vue +12 -0
- package/vue/UiListItem.vue +10 -4
- package/vue/UiTreeItem.vue +1 -1
- package/vue/chunks/UiInput.js +1 -1
- package/vue/chunks/UiInputGroup.js +31 -0
- package/vue/chunks/UiList.js +6 -3
- package/vue/chunks/UiListItem.js +1 -1
- package/vue/chunks/UiTreeItem.js +1 -1
- package/vue/components.css +197 -109
- package/vue/index.d.ts +1 -0
- package/vue/index.js +2 -1
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
margin: 0;
|
|
20
20
|
padding: var(--ui-space-2) var(--ui-space-3);
|
|
21
21
|
appearance: none;
|
|
22
|
-
border: 1px solid var(--ui-control-border, var(--ui-border-strong));
|
|
22
|
+
border: 1px solid var(--ui-input-border, var(--ui-control-border, var(--ui-border-strong)));
|
|
23
23
|
border-radius: var(--ui-input-radius, var(--ui-radius-md));
|
|
24
|
-
background: var(--ui-control-surface, var(--ui-surface-elevated));
|
|
24
|
+
background: var(--ui-input-surface, var(--ui-control-surface, var(--ui-surface-elevated)));
|
|
25
25
|
color: var(--ui-text-primary);
|
|
26
26
|
font: inherit;
|
|
27
27
|
line-height: var(--ui-line-height-md);
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
:host:hover:not(:focus):not(:disabled) {
|
|
47
|
-
border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
|
|
47
|
+
border-color: var(--ui-input-border-hover, var(--ui-control-border-hover, var(--ui-text-secondary)));
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
:host:focus-visible {
|
|
51
|
-
border-color: var(--ui-control-focus, var(--ui-accent-solid));
|
|
51
|
+
border-color: var(--ui-input-focus-border, var(--ui-control-focus, var(--ui-accent-solid)));
|
|
52
52
|
outline: none;
|
|
53
53
|
box-shadow: var(--ui-input-focus-shadow, var(--ui-control-inset), var(--ui-control-focus-halo-shadow));
|
|
54
54
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<template component="ui-input-group">
|
|
2
|
+
<defs>
|
|
3
|
+
<prop name="disabled" type="boolean" default="false">Fades the group's framing to match a disabled input inside it. Disable the input itself too.</prop>
|
|
4
|
+
</defs>
|
|
5
|
+
<div>
|
|
6
|
+
<span class="affix"><slot name="prefix"></slot></span>
|
|
7
|
+
<span class="field"><slot></slot></span>
|
|
8
|
+
<span class="affix"><slot name="suffix"></slot></span>
|
|
9
|
+
</div>
|
|
10
|
+
<style>
|
|
11
|
+
/* An input with fixed text before or after it, such as a domain after a site's name
|
|
12
|
+
("acme" + ".example.com") or slashes around a path. The group draws the field's border and
|
|
13
|
+
focus ring around the input and its affixes together; the input inside drops its own through
|
|
14
|
+
its custom properties, so it is still the one ui-input, with its form behaviour intact. The
|
|
15
|
+
affixes are plain text beside the input, so name the input with a label that says what the
|
|
16
|
+
whole value is. */
|
|
17
|
+
:host {
|
|
18
|
+
--ui-input-border: transparent;
|
|
19
|
+
--ui-input-border-hover: transparent;
|
|
20
|
+
--ui-input-focus-border: transparent;
|
|
21
|
+
--ui-input-shadow: none;
|
|
22
|
+
--ui-input-focus-shadow: none;
|
|
23
|
+
--ui-input-radius: 0;
|
|
24
|
+
--ui-input-surface: transparent;
|
|
25
|
+
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: stretch;
|
|
28
|
+
box-sizing: border-box;
|
|
29
|
+
inline-size: 100%;
|
|
30
|
+
min-inline-size: 0;
|
|
31
|
+
min-block-size: var(--ui-control-size-md);
|
|
32
|
+
border: 1px solid var(--ui-border-strong);
|
|
33
|
+
border-radius: var(--ui-radius-md);
|
|
34
|
+
background: var(--ui-surface-elevated);
|
|
35
|
+
box-shadow: var(--ui-control-inset);
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
transition: border-color var(--ui-motion-fast) var(--ui-motion-ease), box-shadow var(--ui-motion-fast) var(--ui-motion-ease);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:host:hover:not(:focus-within) {
|
|
41
|
+
border-color: var(--ui-text-secondary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:host:focus-within {
|
|
45
|
+
border-color: var(--ui-accent-solid);
|
|
46
|
+
box-shadow:
|
|
47
|
+
var(--ui-control-inset),
|
|
48
|
+
var(--ui-control-focus-halo-shadow);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host:has([aria-invalid="true"], :user-invalid) {
|
|
52
|
+
border-color: var(--ui-danger-solid);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
:host-state([disabled]) {
|
|
56
|
+
background: var(--ui-surface-muted);
|
|
57
|
+
box-shadow: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.field {
|
|
61
|
+
display: flex;
|
|
62
|
+
flex: 1;
|
|
63
|
+
min-inline-size: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.affix {
|
|
67
|
+
display: inline-flex;
|
|
68
|
+
flex: none;
|
|
69
|
+
align-items: center;
|
|
70
|
+
padding-inline: var(--ui-space-2);
|
|
71
|
+
color: var(--ui-text-secondary);
|
|
72
|
+
font-family: var(--ui-font-family-mono);
|
|
73
|
+
font-size: var(--ui-font-size-sm);
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.affix:empty {
|
|
78
|
+
display: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
82
|
+
:host[hidden] {
|
|
83
|
+
display: none;
|
|
84
|
+
}
|
|
85
|
+
</style>
|
|
86
|
+
</template>
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
<prop name="layout" type="rows | grid" default="rows"
|
|
4
4
|
>How the items are laid out. Rows stack the items one per line, for a list read top to bottom. Grid sets them in as many columns as fit, each at least
|
|
5
5
|
--ui-list-min-item-width (14rem) wide, for card items such as pinned or featured entries.</prop>
|
|
6
|
+
<prop name="density" type="comfortable | compact" default="comfortable"
|
|
7
|
+
>How much room each item takes. comfortable is a full row, easy to point at, for lists of things to open; compact sets items close together with no row
|
|
8
|
+
padding, for a short list of facts inside other content, such as the features a plan includes.</prop>
|
|
6
9
|
</defs>
|
|
7
10
|
<ul role="list"><slot></slot></ul>
|
|
8
11
|
<style>
|
|
@@ -19,6 +22,15 @@
|
|
|
19
22
|
list-style: none;
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
/* Compact passes its size to the items through private properties, which cross into each item. */
|
|
26
|
+
:host-state([density="compact"]) {
|
|
27
|
+
--_ui-list-item-min-size: 0;
|
|
28
|
+
--_ui-list-item-padding-block: 0;
|
|
29
|
+
--_ui-list-item-padding-inline: 0;
|
|
30
|
+
--_ui-list-item-title-weight: var(--ui-font-normal);
|
|
31
|
+
gap: var(--ui-list-gap, var(--ui-space-2));
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
:host-state([layout="grid"]) {
|
|
23
35
|
display: grid;
|
|
24
36
|
grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--ui-list-min-item-width, 14rem)), 1fr));
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
align-items: center;
|
|
33
33
|
gap: var(--ui-list-item-gap, var(--ui-space-3));
|
|
34
34
|
min-inline-size: 0;
|
|
35
|
-
min-block-size: var(--ui-control-size, 2.5rem);
|
|
36
|
-
padding-block: var(--ui-list-item-padding-block, var(--ui-space-2));
|
|
37
|
-
padding-inline: var(--ui-list-item-padding-inline, var(--ui-space-3));
|
|
35
|
+
min-block-size: var(--_ui-list-item-min-size, var(--ui-control-size, 2.5rem));
|
|
36
|
+
padding-block: var(--ui-list-item-padding-block, var(--_ui-list-item-padding-block, var(--ui-space-2)));
|
|
37
|
+
padding-inline: var(--ui-list-item-padding-inline, var(--_ui-list-item-padding-inline, var(--ui-space-3)));
|
|
38
38
|
border-radius: var(--ui-radius-md);
|
|
39
39
|
color: var(--ui-text-primary);
|
|
40
40
|
transition: background-color var(--ui-motion-fast) var(--ui-motion-ease), border-color var(--ui-motion-fast) var(--ui-motion-ease);
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
|
|
105
105
|
.title {
|
|
106
106
|
font-size: var(--ui-font-size-md);
|
|
107
|
-
font-weight: var(--ui-font-medium);
|
|
107
|
+
font-weight: var(--_ui-list-item-title-weight, var(--ui-font-medium));
|
|
108
108
|
line-height: var(--ui-line-height-tight);
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -298,7 +298,7 @@
|
|
|
298
298
|
/* A hovered row reads its whole name: the label slides far enough to show the end, waits
|
|
299
299
|
there, and comes back. Only when it actually overflows — the controller measures by how
|
|
300
300
|
much — after the controls have taken their place over its end — and hands over the distance
|
|
301
|
-
and a duration from it, so
|
|
301
|
+
and a duration from it, so every name moves at the same speed. */
|
|
302
302
|
.row[data-ui-marquee] > .label > .label-text {
|
|
303
303
|
/* Once, and it stays at the end while the pointer is there: a name that keeps sliding back
|
|
304
304
|
and forth under the pointer is harder to read than one that arrives and holds. */
|
|
@@ -102,7 +102,7 @@ export default function controller(host) {
|
|
|
102
102
|
* at its own width; it has to end where the fade before the controls begins, since the controls
|
|
103
103
|
* overlay the label's end rather than taking width from it.
|
|
104
104
|
*/
|
|
105
|
-
const MARQUEE_SPEED = 36; // CSS pixels per second.
|
|
105
|
+
const MARQUEE_SPEED = 36; // CSS pixels per second, for every name: a clamped duration made short slides crawl.
|
|
106
106
|
// The tree sets this for its items; an item's own prop overrides it either way.
|
|
107
107
|
const marqueeWanted = () => host.state.marquee
|
|
108
108
|
|| getComputedStyle(element).getPropertyValue("--ui-tree-item-marquee").trim() === "1";
|
|
@@ -121,10 +121,7 @@ export default function controller(host) {
|
|
|
121
121
|
const lead = icon?.width ? (rightToLeft ? icon.right - cell.right : cell.left - icon.left) : 0;
|
|
122
122
|
row.style.setProperty("--_marquee-lead", `${Math.max(0, lead)}px`);
|
|
123
123
|
row.style.setProperty("--_marquee-distance", `${rightToLeft ? distance : -distance}px`);
|
|
124
|
-
row.style.setProperty(
|
|
125
|
-
"--_marquee-duration",
|
|
126
|
-
`${Math.min(10, Math.max(1.4, distance / MARQUEE_SPEED)).toFixed(2)}s`
|
|
127
|
-
);
|
|
124
|
+
row.style.setProperty("--_marquee-duration", `${(distance / MARQUEE_SPEED).toFixed(2)}s`);
|
|
128
125
|
row.dataset.uiMarquee = "";
|
|
129
126
|
};
|
|
130
127
|
const stopMarquee = () => {
|