@threadlabs/looma 0.25.1 → 0.25.2

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.
@@ -1,6 +1,9 @@
1
1
  <template component="ui-input-group" controller="./ui-input-group.js">
2
2
  <defs>
3
3
  <prop name="multiline" type="boolean" default="false">Groups a Textarea with an action below its text inside the shared frame.</prop>
4
+ <prop name="actionPosition" type="keyword" values="below, top-end" default="below"
5
+ >In a multiline group, below keeps the action under the text. top-end places it inside the textarea at its upper end and reserves text padding for its
6
+ measured width.</prop>
4
7
  <prop name="prefixKind" type="keyword" values="text, icon" default="text"
5
8
  >Text affixes have their own framing. An icon prefix shares the field surface and uses one compact icon-to-value gap.</prop>
6
9
  <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>
@@ -201,6 +204,24 @@
201
204
  padding-block-start: 0;
202
205
  }
203
206
 
207
+ /* The same textarea keeps its full resizeable box. Its text reserves the action's live width,
208
+ so a translated label or pending indicator cannot cover what the person types. */
209
+ :host([multiline][actionPosition="top-end"]) {
210
+ --_ui-default-textarea-padding-inline-end: calc(var(--_ui-input-group-action-inline-size, 7rem) + var(--ui-space-3));
211
+ }
212
+
213
+ :host([multiline][actionPosition="top-end"]) .field {
214
+ grid-row: 1;
215
+ }
216
+
217
+ :host([multiline][actionPosition="top-end"]) .action {
218
+ grid-column: 2;
219
+ grid-row: 1;
220
+ align-self: start;
221
+ justify-self: end;
222
+ padding: var(--ui-space-2);
223
+ }
224
+
204
225
  .affix:empty,
205
226
  .action:empty {
206
227
  display: none;
@@ -20,7 +20,22 @@ function connect(host) {
20
20
  let owned = [];
21
21
  let described = null;
22
22
  const warned = new Set();
23
+ let action = null;
24
+ const measureAction = () => {
25
+ const width = action?.getBoundingClientRect().width ?? 0;
26
+ element.style.setProperty("--_ui-input-group-action-inline-size", `${width}px`);
27
+ };
28
+ // Observe the actual slot surface rather than estimating a label's width. This also catches
29
+ // pending indicators, font loading, touch target sizing and translated labels.
30
+ const actionObserver = new ResizeObserver(measureAction);
23
31
  const wire = () => {
32
+ const nextAction = element.querySelector(":scope > .action");
33
+ if (action !== nextAction) {
34
+ if (action) actionObserver.unobserve(action);
35
+ action = nextAction;
36
+ if (action) actionObserver.observe(action);
37
+ }
38
+ measureAction();
24
39
  const input = element.querySelector(".field :is(input, textarea)");
25
40
  const affixes = Array.from(element.querySelectorAll(":scope > .affix")).filter((affix) => {
26
41
  const text = affix.textContent.trim() !== "" && !affix.querySelector(INTERACTIVE);
@@ -61,6 +76,8 @@ function connect(host) {
61
76
  wire();
62
77
  return () => {
63
78
  observer.disconnect();
79
+ actionObserver.disconnect();
80
+ element.style.removeProperty("--_ui-input-group-action-inline-size");
64
81
  element.removeEventListener("mousedown", onMousedown);
65
82
  element.removeEventListener("click", onClick);
66
83
  };
@@ -70,6 +70,10 @@
70
70
  syntax: "*";
71
71
  inherits: false;
72
72
  }
73
+ @property --ui-textarea-padding-inline-end {
74
+ syntax: "*";
75
+ inherits: false;
76
+ }
73
77
 
74
78
  :host {
75
79
  box-sizing: border-box;
@@ -80,6 +84,7 @@
80
84
  margin: 0;
81
85
  --_padding-block: var(--ui-space-2);
82
86
  padding: var(--ui-space-2) var(--ui-space-3);
87
+ padding-inline-end: var(--ui-textarea-padding-inline-end, var(--_ui-default-textarea-padding-inline-end, var(--ui-space-3)));
83
88
  appearance: none;
84
89
  resize: vertical;
85
90
  border: var(--ui-textarea-border-width, var(--_ui-default-textarea-border-width, var(--ui-border-width))) solid
@@ -148,12 +153,14 @@
148
153
  :host([size="sm"]) {
149
154
  --_padding-block: var(--ui-space-1);
150
155
  padding: var(--ui-space-1) var(--ui-space-2);
156
+ padding-inline-end: var(--ui-textarea-padding-inline-end, var(--_ui-default-textarea-padding-inline-end, var(--ui-space-2)));
151
157
  font-size: var(--ui-font-size-sm);
152
158
  }
153
159
 
154
160
  :host([size="lg"]) {
155
161
  --_padding-block: var(--ui-space-3);
156
162
  padding: var(--ui-space-3) var(--ui-space-4);
163
+ padding-inline-end: var(--ui-textarea-padding-inline-end, var(--_ui-default-textarea-padding-inline-end, var(--ui-space-4)));
157
164
  font-size: var(--ui-font-size-md);
158
165
  }
159
166