@threadlabs/looma 0.25.0 → 0.25.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-input-group/ui-input-group.html +34 -5
- package/components/ui-input-group/ui-input-group.js +2 -2
- package/components/ui-textarea/ui-textarea.html +42 -14
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-input-group.css +35 -5
- package/styles/ui-textarea.css +42 -14
- package/vanilla/UiInputGroup.d.ts +1 -0
- package/vanilla/UiInputGroup.js +1 -1
- package/vue/UiInputGroup.d.ts +9 -0
- package/vue/UiInputGroup.vue +56 -7
- package/vue/UiTextarea.vue +76 -15
- package/vue/chunks/UiInputGroup.js +29 -3
- package/vue/chunks/UiTextarea.js +1 -1
- package/vue/components.css +139 -52
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template component="ui-input-group" controller="./ui-input-group.js">
|
|
2
2
|
<defs>
|
|
3
|
+
<prop name="multiline" type="boolean" default="false">Groups a Textarea with an action below its text inside the shared frame.</prop>
|
|
3
4
|
<prop name="prefixKind" type="keyword" values="text, icon" default="text"
|
|
4
5
|
>Text affixes have their own framing. An icon prefix shares the field surface and uses one compact icon-to-value gap.</prop>
|
|
5
6
|
<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>
|
|
@@ -46,6 +47,17 @@
|
|
|
46
47
|
--_ui-default-input-focus-outline: none;
|
|
47
48
|
--_ui-default-input-radius: 0;
|
|
48
49
|
--_ui-default-input-surface: transparent;
|
|
50
|
+
--_ui-default-textarea-border-width: 0;
|
|
51
|
+
--_ui-default-textarea-border: transparent;
|
|
52
|
+
--_ui-default-textarea-border-hover: transparent;
|
|
53
|
+
--_ui-default-textarea-focus-border: transparent;
|
|
54
|
+
--_ui-default-textarea-invalid-border: transparent;
|
|
55
|
+
--_ui-default-textarea-invalid-focus-shadow: none;
|
|
56
|
+
--_ui-default-textarea-shadow: none;
|
|
57
|
+
--_ui-default-textarea-focus-shadow: none;
|
|
58
|
+
--_ui-default-textarea-focus-outline: none;
|
|
59
|
+
--_ui-default-textarea-radius: 0;
|
|
60
|
+
--_ui-default-textarea-surface: transparent;
|
|
49
61
|
|
|
50
62
|
display: flex;
|
|
51
63
|
align-items: stretch;
|
|
@@ -79,13 +91,13 @@
|
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
|
|
82
|
-
:host:hover:not(:has(input:focus, input:disabled, input:read-only, [aria-invalid="true"], :user-invalid)) {
|
|
94
|
+
:host:hover:not(:has(:is(input, textarea):focus, :is(input, textarea):disabled, :is(input, textarea):read-only, [aria-invalid="true"], :user-invalid)) {
|
|
83
95
|
border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
/* The ring shows when the field's input would show its own: when it is focus-visible, which a
|
|
87
99
|
text input is for a pointer as well as a keyboard. A focused action button draws its own. */
|
|
88
|
-
:host:has(.field input:focus-visible) {
|
|
100
|
+
:host:has(.field :is(input, textarea):focus-visible) {
|
|
89
101
|
border-color: var(--ui-control-focus, var(--ui-accent-solid));
|
|
90
102
|
box-shadow:
|
|
91
103
|
var(--ui-control-inset),
|
|
@@ -96,7 +108,7 @@
|
|
|
96
108
|
border-color: var(--ui-input-group-invalid-border, var(--ui-field-danger, var(--ui-danger-solid)));
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
:host:has(input:is([aria-invalid="true"], :user-invalid):focus-visible) {
|
|
111
|
+
:host:has(:is(input, textarea):is([aria-invalid="true"], :user-invalid):focus-visible) {
|
|
100
112
|
box-shadow: var(
|
|
101
113
|
--ui-input-group-invalid-focus-shadow,
|
|
102
114
|
var(--ui-control-inset),
|
|
@@ -110,14 +122,14 @@
|
|
|
110
122
|
|
|
111
123
|
/* Forced colors drop box shadows, so the focus ring becomes an outline. */
|
|
112
124
|
@media (forced-colors: active) {
|
|
113
|
-
:host:has(input:focus-visible) {
|
|
125
|
+
:host:has(:is(input, textarea):focus-visible) {
|
|
114
126
|
outline: var(--ui-focus-width) solid Highlight;
|
|
115
127
|
outline-offset: var(--ui-border-width);
|
|
116
128
|
}
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
:host([disabled]),
|
|
120
|
-
:host:has(input:disabled) {
|
|
132
|
+
:host:has(:is(input, textarea):disabled) {
|
|
121
133
|
background: var(--ui-control-surface-disabled, var(--ui-surface-muted));
|
|
122
134
|
box-shadow: none;
|
|
123
135
|
cursor: not-allowed;
|
|
@@ -172,6 +184,23 @@
|
|
|
172
184
|
padding-inline: var(--ui-space-1);
|
|
173
185
|
}
|
|
174
186
|
|
|
187
|
+
/* Multiline text owns the first row; its action remains inside the same frame below it. */
|
|
188
|
+
:host([multiline]) {
|
|
189
|
+
display: grid;
|
|
190
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
:host([multiline]) .field {
|
|
194
|
+
grid-column: 2;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
:host([multiline]) .action {
|
|
198
|
+
grid-column: 1 / -1;
|
|
199
|
+
justify-content: end;
|
|
200
|
+
padding: var(--ui-space-2);
|
|
201
|
+
padding-block-start: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
175
204
|
.affix:empty,
|
|
176
205
|
.action:empty {
|
|
177
206
|
display: none;
|
|
@@ -21,7 +21,7 @@ function connect(host) {
|
|
|
21
21
|
let described = null;
|
|
22
22
|
const warned = new Set();
|
|
23
23
|
const wire = () => {
|
|
24
|
-
const input = element.querySelector(".field input");
|
|
24
|
+
const input = element.querySelector(".field :is(input, textarea)");
|
|
25
25
|
const affixes = Array.from(element.querySelectorAll(":scope > .affix")).filter((affix) => {
|
|
26
26
|
const text = affix.textContent.trim() !== "" && !affix.querySelector(INTERACTIVE);
|
|
27
27
|
if (text) affix.setAttribute("aria-hidden", "true");
|
|
@@ -50,7 +50,7 @@ function connect(host) {
|
|
|
50
50
|
};
|
|
51
51
|
// Click, not pointerdown: a tap's click is a user activation, so a touch keyboard opens.
|
|
52
52
|
const onClick = (event) => {
|
|
53
|
-
if (pressedAround(event) && !host.props.disabled.value) element.querySelector(".field input")?.focus();
|
|
53
|
+
if (pressedAround(event) && !host.props.disabled.value) element.querySelector(".field :is(input, textarea)")?.focus();
|
|
54
54
|
};
|
|
55
55
|
element.addEventListener("mousedown", onMousedown);
|
|
56
56
|
element.addEventListener("click", onClick);
|
|
@@ -26,6 +26,30 @@
|
|
|
26
26
|
></textarea>
|
|
27
27
|
<style>
|
|
28
28
|
/* This component's hooks style the element they are set on, and never a nested one. */
|
|
29
|
+
@property --ui-textarea-border-width {
|
|
30
|
+
syntax: "*";
|
|
31
|
+
inherits: false;
|
|
32
|
+
}
|
|
33
|
+
@property --ui-textarea-border {
|
|
34
|
+
syntax: "*";
|
|
35
|
+
inherits: false;
|
|
36
|
+
}
|
|
37
|
+
@property --ui-textarea-border-hover {
|
|
38
|
+
syntax: "*";
|
|
39
|
+
inherits: false;
|
|
40
|
+
}
|
|
41
|
+
@property --ui-textarea-focus-border {
|
|
42
|
+
syntax: "*";
|
|
43
|
+
inherits: false;
|
|
44
|
+
}
|
|
45
|
+
@property --ui-textarea-focus-outline {
|
|
46
|
+
syntax: "*";
|
|
47
|
+
inherits: false;
|
|
48
|
+
}
|
|
49
|
+
@property --ui-textarea-surface {
|
|
50
|
+
syntax: "*";
|
|
51
|
+
inherits: false;
|
|
52
|
+
}
|
|
29
53
|
@property --ui-textarea-focus-shadow {
|
|
30
54
|
syntax: "*";
|
|
31
55
|
inherits: false;
|
|
@@ -58,13 +82,14 @@
|
|
|
58
82
|
padding: var(--ui-space-2) var(--ui-space-3);
|
|
59
83
|
appearance: none;
|
|
60
84
|
resize: vertical;
|
|
61
|
-
border: var(--ui-border-width
|
|
62
|
-
|
|
63
|
-
|
|
85
|
+
border: var(--ui-textarea-border-width, var(--_ui-default-textarea-border-width, var(--ui-border-width))) solid
|
|
86
|
+
var(--ui-textarea-border, var(--_ui-default-textarea-border, var(--ui-control-border, var(--ui-border-strong))));
|
|
87
|
+
border-radius: var(--ui-textarea-radius, var(--_ui-default-textarea-radius, var(--ui-field-radius, var(--ui-radius-md))));
|
|
88
|
+
background: var(--ui-textarea-surface, var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
|
|
64
89
|
color: var(--ui-text-primary);
|
|
65
90
|
font: inherit;
|
|
66
91
|
line-height: var(--ui-line-height-md);
|
|
67
|
-
box-shadow: var(--ui-textarea-shadow, var(--ui-control-inset));
|
|
92
|
+
box-shadow: var(--ui-textarea-shadow, var(--_ui-default-textarea-shadow, var(--ui-control-inset)));
|
|
68
93
|
transition:
|
|
69
94
|
border-color var(--ui-motion-fast) var(--ui-motion-ease),
|
|
70
95
|
box-shadow var(--ui-motion-fast) var(--ui-motion-ease),
|
|
@@ -83,29 +108,32 @@
|
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
:host:hover:not(:focus):not(:disabled):not(:read-only):not([aria-invalid="true"]):not(:user-invalid) {
|
|
86
|
-
border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
|
|
111
|
+
border-color: var(--ui-textarea-border-hover, var(--_ui-default-textarea-border-hover, var(--ui-control-border-hover, var(--ui-text-secondary))));
|
|
87
112
|
}
|
|
88
113
|
|
|
89
114
|
:host:focus-visible {
|
|
90
|
-
border-color: var(--ui-control-focus, var(--ui-accent-solid));
|
|
91
|
-
outline: none;
|
|
92
|
-
box-shadow: var(--ui-textarea-focus-shadow, var(--ui-control-inset), var(--ui-control-focus-halo-shadow));
|
|
115
|
+
border-color: var(--ui-textarea-focus-border, var(--_ui-default-textarea-focus-border, var(--ui-control-focus, var(--ui-accent-solid))));
|
|
116
|
+
outline: var(--ui-textarea-focus-outline, var(--_ui-default-textarea-focus-outline, none));
|
|
117
|
+
box-shadow: var(--ui-textarea-focus-shadow, var(--_ui-default-textarea-focus-shadow, var(--ui-control-inset), var(--ui-control-focus-halo-shadow)));
|
|
93
118
|
}
|
|
94
119
|
|
|
95
120
|
/* The app's invalid flag, or the browser's own verdict once the user has left an invalid field. */
|
|
96
121
|
:host[aria-invalid="true"],
|
|
97
122
|
:host:user-invalid {
|
|
98
|
-
border-color: var(--ui-textarea-invalid-border, var(--ui-field-danger, var(--ui-danger-solid)));
|
|
123
|
+
border-color: var(--ui-textarea-invalid-border, var(--_ui-default-textarea-invalid-border, var(--ui-field-danger, var(--ui-danger-solid))));
|
|
99
124
|
}
|
|
100
125
|
|
|
101
126
|
:host:is([aria-invalid="true"], :user-invalid):focus-visible {
|
|
102
127
|
box-shadow: var(
|
|
103
128
|
--ui-textarea-invalid-focus-shadow,
|
|
104
|
-
var(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
129
|
+
var(
|
|
130
|
+
--_ui-default-textarea-invalid-focus-shadow,
|
|
131
|
+
var(--ui-control-inset),
|
|
132
|
+
0 0 0 calc(var(--ui-focus-width) * 1.5) color-mix(
|
|
133
|
+
in srgb,
|
|
134
|
+
var(--ui-textarea-invalid-border, var(--_ui-default-textarea-invalid-border, var(--ui-field-danger, var(--ui-danger-solid)))) 22%,
|
|
135
|
+
transparent
|
|
136
|
+
)
|
|
109
137
|
)
|
|
110
138
|
);
|
|
111
139
|
}
|