@threadlabs/looma 0.23.14 → 0.23.16

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.
@@ -11,6 +11,9 @@
11
11
  <prop name="size" type="keyword" values="sm, md, lg" default="md"
12
12
  >Button and icon size together: sm is 1.75rem with a small icon, md is 2rem, and lg is 2.5rem with a large icon. On touch, every size gets an invisible hit
13
13
  area of at least 44px.</prop>
14
+ <prop name="matchButton" type="boolean" default="false"
15
+ >Matches a boxed Button of the same size when the two share a flex row. Uses the control-size theme tokens and stretches to the row's height, including
16
+ touch-sized controls. Leave it off for compact toolbar and inline icon buttons.</prop>
14
17
  <prop name="variant" type="keyword" values="ghost, outline, solid" default="ghost"
15
18
  >Emphasis. ghost shows only the icon until it is hovered, for toolbars and dense rows; outline adds a border on the default surface; solid fills with the
16
19
  accent colour, for the one primary action in a group.</prop>
@@ -23,6 +26,7 @@
23
26
  from:disabled="disabled"
24
27
  type="button"
25
28
  from:aria-label="label"
29
+ from:data-match-button="matchButton"
26
30
  from:aria-disabled="{ true: 'true', false: null }[format('%s', loading or pending)]"
27
31
  from:aria-busy="loading or pending"
28
32
  >
@@ -245,6 +249,29 @@
245
249
  min-block-size: var(--ui-icon-button-size, var(--_size));
246
250
  }
247
251
 
252
+ /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
253
+ :host-state([matchButton]) {
254
+ --_size: var(--ui-control-size-md);
255
+ block-size: auto;
256
+ align-self: stretch;
257
+ }
258
+
259
+ :host-state([matchButton][size="sm"]) {
260
+ --_size: var(--ui-control-size-sm);
261
+ }
262
+
263
+ :host-state([matchButton][size="lg"]) {
264
+ --_size: var(--ui-control-size-lg);
265
+ }
266
+
267
+ @media (pointer: coarse) {
268
+ :host-state([matchButton]) {
269
+ inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
270
+ min-inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
271
+ min-block-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
272
+ }
273
+ }
274
+
248
275
  :host-state([round]) {
249
276
  border-radius: var(--ui-radius-round);
250
277
  }
@@ -133,9 +133,14 @@
133
133
  /* Under touch a small field is still a touch-sized target, as a small button is, and keeps
134
134
  body-size text: below 16px, iOS zooms the page into the focused field. */
135
135
  @media (pointer: coarse) {
136
+ :host,
137
+ :host-state([size="sm"]),
138
+ :host-state([size="lg"]) {
139
+ font-size: var(--ui-font-size-md);
140
+ }
141
+
136
142
  :host-state([size="sm"]) {
137
143
  min-block-size: var(--ui-input-min-block-size, var(--_ui-default-input-min-block-size, var(--ui-control-min-block-size)));
138
- font-size: inherit;
139
144
  }
140
145
  }
141
146
 
@@ -470,7 +470,7 @@
470
470
  }
471
471
 
472
472
  /* Without hover there is no reveal, so the controls keep their own column. */
473
- @media (hover: none) {
473
+ @media (hover: none), (pointer: coarse) {
474
474
  .row {
475
475
  grid-template-columns: var(--_tree-disclosure-size) auto minmax(0, 1fr) auto;
476
476
  }
@@ -484,6 +484,37 @@
484
484
  opacity: 1;
485
485
  pointer-events: auto;
486
486
  }
487
+
488
+ .row:is(:hover, :focus-within) > .label,
489
+ .row:is(:hover, :focus-within) > .label:dir(rtl),
490
+ :host[data-move-source] > .row > .label,
491
+ :host[data-move-source] > .row > .label:dir(rtl) {
492
+ mask-image: none;
493
+ }
494
+
495
+ .row[data-ui-marquee] > .label {
496
+ mask-image: linear-gradient(
497
+ to right,
498
+ transparent var(--_marquee-icon-width, 0px),
499
+ #000 calc(var(--_marquee-lead, 0px) + var(--_ui-tree-item-label-padding-inline, var(--ui-space-2)))
500
+ );
501
+ }
502
+
503
+ .row[data-ui-marquee] > .label:dir(rtl) {
504
+ mask-image: linear-gradient(
505
+ to left,
506
+ transparent var(--_marquee-icon-width, 0px),
507
+ #000 calc(var(--_marquee-lead, 0px) + var(--_ui-tree-item-label-padding-inline, var(--ui-space-2)))
508
+ );
509
+ }
510
+
511
+ :host[data-selection-mode="multiple"] > .row {
512
+ grid-template-columns: var(--_tree-disclosure-size) 1.25rem auto minmax(0, 1fr) auto;
513
+ }
514
+
515
+ :host[data-selection-mode="multiple"] > .row > .actions {
516
+ grid-column: 5;
517
+ }
487
518
  }
488
519
 
489
520
  /* The handle sits beside what it drags. A leaf row has no disclosure, so the handle takes that
@@ -625,6 +656,24 @@
625
656
  grid-column: 5;
626
657
  }
627
658
 
659
+ @media (hover: none), (pointer: coarse) {
660
+ html[data-ui-input-modality="touch"] :host .row {
661
+ grid-template-columns: 44px var(--_tree-disclosure-size) auto minmax(0, 1fr) auto;
662
+ }
663
+
664
+ html[data-ui-input-modality="touch"] :host .actions {
665
+ grid-column: 5;
666
+ }
667
+
668
+ html[data-ui-input-modality="touch"] :host[data-selection-mode="multiple"] > .row {
669
+ grid-template-columns: 44px var(--_tree-disclosure-size) 44px auto minmax(0, 1fr) auto;
670
+ }
671
+
672
+ html[data-ui-input-modality="touch"] :host[data-selection-mode="multiple"] > .row > .actions {
673
+ grid-column: 6;
674
+ }
675
+ }
676
+
628
677
  @media (prefers-reduced-motion: reduce) {
629
678
  .row,
630
679
  .disclosure-icon,
@@ -143,7 +143,8 @@ export default function controller(host) {
143
143
  labelText.style.flex = labelText.style.inlineSize = "";
144
144
  const cell = label.getBoundingClientRect();
145
145
  const icon = leading?.getBoundingClientRect();
146
- const stop = (actions?.offsetWidth ?? 0) + parseFloat(getComputedStyle(label).columnGap);
146
+ const overlayActions = actions && getComputedStyle(actions).position === "absolute";
147
+ const stop = overlayActions ? actions.offsetWidth + parseFloat(getComputedStyle(label).columnGap) : 0;
147
148
  const distance = Math.ceil(rightToLeft ? cell.left + stop - end : end - (cell.right - stop));
148
149
  if (distance <= 0) return;
149
150
  const lead = icon?.width ? (rightToLeft ? icon.right - cell.right : cell.left - icon.left) : 0;