@threadlabs/looma 0.11.4 → 0.11.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.11.4",
3
+ "version": "0.11.6",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -222,6 +222,23 @@
222
222
  }
223
223
  }
224
224
 
225
+ /* Under touch, a link-style button's press lands within the control minimum: an invisible hit
226
+ area, centred on it, like IconButton's. A boxed button grows to the minimum itself (below);
227
+ a link-style one keeps its text size, so a standalone one ("See all" under a list) needs the
228
+ area. Only the link needs it: a hit area on every button would reach over its neighbours. */
229
+ html[data-ui-input-modality="touch"] :scope[data-ui-button-state~="variant=link"] {
230
+ position: relative;
231
+ }
232
+
233
+ html[data-ui-input-modality="touch"] :scope[data-ui-button-state~="variant=link"]::after {
234
+ position: absolute;
235
+ inset: 50% auto auto 50%;
236
+ inline-size: max(100%, var(--ui-control-min-block-size));
237
+ block-size: max(100%, var(--ui-control-min-block-size));
238
+ transform: translate(-50%, -50%);
239
+ content: "";
240
+ }
241
+
225
242
  /* Link: an inline text action. No box, padding, or minimum height (inline targets are exempt under
226
243
  WCAG 2.5.8); the inherited font; an underline that strengthens on hover; a visible focus ring. */
227
244
  :scope[data-ui-button-state~="variant=link"] {
@@ -302,6 +319,11 @@
302
319
  @media (pointer: coarse) {
303
320
  }
304
321
 
322
+ /* Under touch, a link-style button's press lands within the control minimum: an invisible hit
323
+ area, centred on it, like IconButton's. A boxed button grows to the minimum itself (below);
324
+ a link-style one keeps its text size, so a standalone one ("See all" under a list) needs the
325
+ area. Only the link needs it: a hit area on every button would reach over its neighbours. */
326
+
305
327
  /* Link: an inline text action. No box, padding, or minimum height (inline targets are exempt under
306
328
  WCAG 2.5.8); the inherited font; an underline that strengthens on hover; a visible focus ring. */
307
329
 
package/vue/UiButton.vue CHANGED
@@ -299,6 +299,25 @@ function attribute(value: unknown): any {
299
299
  }
300
300
  }
301
301
 
302
+ /* Under touch, a link-style button's press lands within the control minimum: an invisible hit
303
+ area, centred on it, like IconButton's. A boxed button grows to the minimum itself (below);
304
+ a link-style one keeps its text size, so a standalone one ("See all" under a list) needs the
305
+ area. Only the link needs it: a hit area on every button would reach over its neighbours. */
306
+ html[data-ui-input-modality="touch"]
307
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"] {
308
+ position: relative;
309
+ }
310
+
311
+ html[data-ui-input-modality="touch"]
312
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"]::after {
313
+ position: absolute;
314
+ inset: 50% auto auto 50%;
315
+ inline-size: max(100%, var(--ui-control-min-block-size));
316
+ block-size: max(100%, var(--ui-control-min-block-size));
317
+ transform: translate(-50%, -50%);
318
+ content: "";
319
+ }
320
+
302
321
  /* Link: an inline text action. No box, padding, or minimum height (inline targets are exempt under
303
322
  WCAG 2.5.8); the inherited font; an underline that strengthens on hover; a visible focus ring. */
304
323
  [data-component~="ui-button"][data-ui-button-state~="variant=link"] {
@@ -83,6 +83,6 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
83
83
  ]);
84
84
  };
85
85
  }
86
- }), [["__scopeId", "data-v-0c121308"]]);
86
+ }), [["__scopeId", "data-v-97872575"]]);
87
87
  //#endregion
88
88
  export { UiButton_default as t };
@@ -368,7 +368,7 @@ ol[data-v-0d86d58e] {
368
368
  display: none;
369
369
  }
370
370
 
371
- [data-component~="ui-button"][data-v-0c121308] {
371
+ [data-component~="ui-button"][data-v-97872575] {
372
372
  --_hue: var(--ui-accent);
373
373
  --_hue-hover: var(--ui-accent-hover);
374
374
  --_hue-active: var(--ui-accent-active);
@@ -387,15 +387,15 @@ ol[data-v-0d86d58e] {
387
387
  vertical-align: middle;
388
388
  color: var(--_tone-text);
389
389
  }
390
- [data-component~="ui-button"][data-ui-button-state~="align=start"][data-v-0c121308] {
390
+ [data-component~="ui-button"][data-ui-button-state~="align=start"][data-v-97872575] {
391
391
  justify-content: flex-start;
392
392
  text-align: start;
393
393
  }
394
- [data-component~="ui-button"][data-ui-button-state~="stretch"][data-v-0c121308] {
394
+ [data-component~="ui-button"][data-ui-button-state~="stretch"][data-v-97872575] {
395
395
  display: flex;
396
396
  inline-size: 100%;
397
397
  }
398
- [data-component~="ui-button"][data-v-0c121308] {
398
+ [data-component~="ui-button"][data-v-97872575] {
399
399
  appearance: none;
400
400
  min-block-size: var(--ui-button-min-block-size, var(--ui-control-size-md));
401
401
  border-style: solid;
@@ -420,17 +420,17 @@ ol[data-v-0d86d58e] {
420
420
  margin: 0;
421
421
  }
422
422
  @supports (text-box-trim: trim-both) {
423
- [data-component~="ui-button"][data-v-0c121308] {
423
+ [data-component~="ui-button"][data-v-97872575] {
424
424
  text-box-trim: trim-both;
425
425
  text-box-edge: cap alphabetic;
426
426
  }
427
427
  }
428
- [data-component~="ui-button"][data-ui-button-state~="size=sm"][data-v-0c121308] {
428
+ [data-component~="ui-button"][data-ui-button-state~="size=sm"][data-v-97872575] {
429
429
  min-block-size: var(--ui-control-size-sm);
430
430
  padding: var(--ui-space-1) var(--ui-space-2);
431
431
  font-size: var(--ui-font-size-sm);
432
432
  }
433
- [data-component~="ui-button"][data-ui-button-state~="size=lg"][data-v-0c121308] {
433
+ [data-component~="ui-button"][data-ui-button-state~="size=lg"][data-v-97872575] {
434
434
  min-block-size: var(--ui-control-size-lg);
435
435
  padding: var(--ui-space-3) var(--ui-space-4);
436
436
  font-size: var(--ui-font-size-md);
@@ -438,29 +438,29 @@ ol[data-v-0d86d58e] {
438
438
 
439
439
  /* A link is never :enabled, so interactive states test "not unavailable" instead: for a button that
440
440
  is exactly :enabled, at the same specificity, and it also matches a link that can be followed. */
441
- [data-component~="ui-button"][data-v-0c121308]:hover:not(:disabled, [aria-disabled="true"]) {
441
+ [data-component~="ui-button"][data-v-97872575]:hover:not(:disabled, [aria-disabled="true"]) {
442
442
  border-color: var(--ui-button-hover-border, var(--_tone-hover));
443
443
  background-color: var(--ui-button-hover-surface, oklch(from var(--_tone) l c h / 12%));
444
444
  }
445
445
 
446
446
  /* Pressed reads as pressed in: the highlight goes, and the shadow moves inside. */
447
- [data-component~="ui-button"][data-v-0c121308]:active:not(:disabled, [aria-disabled="true"]) {
447
+ [data-component~="ui-button"][data-v-97872575]:active:not(:disabled, [aria-disabled="true"]) {
448
448
  background-color: var(--ui-button-active-surface, oklch(from var(--_tone) l c h / 18%));
449
449
  background-image: none;
450
450
  box-shadow: var(--ui-pressed);
451
451
  }
452
- [data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-0c121308],
453
- [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-0c121308] {
452
+ [data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-97872575],
453
+ [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-97872575] {
454
454
  border-color: var(--_tone);
455
455
  background-color: var(--_tone);
456
456
  color: var(--_on-tone);
457
457
  box-shadow: var(--ui-button-solid-shadow, var(--ui-raised));
458
458
  }
459
- :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-0c121308], [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-0c121308]):hover:not(:disabled, [aria-disabled="true"]) {
459
+ :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-97872575], [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-97872575]):hover:not(:disabled, [aria-disabled="true"]) {
460
460
  background-color: var(--_tone-hover);
461
461
  border-color: var(--_tone-hover);
462
462
  }
463
- :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-0c121308], [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-0c121308]):active:not(:disabled, [aria-disabled="true"]) {
463
+ :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-97872575], [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-97872575]):active:not(:disabled, [aria-disabled="true"]) {
464
464
  background-color: var(--_tone-active);
465
465
  border-color: var(--_tone-active);
466
466
  background-image: none;
@@ -469,43 +469,43 @@ ol[data-v-0d86d58e] {
469
469
 
470
470
  /* Tone is the colour, variant is the volume. Every pairing works: a danger outline is a
471
471
  destructive secondary action, not a special case. */
472
- [data-component~="ui-button"][data-ui-button-state~="tone=neutral"][data-v-0c121308] {
472
+ [data-component~="ui-button"][data-ui-button-state~="tone=neutral"][data-v-97872575] {
473
473
  --_hue: var(--ui-text);
474
474
  --_hue-hover: var(--ui-text);
475
475
  --_hue-active: var(--ui-text);
476
476
  --_hue-text: var(--ui-text);
477
477
  --_on-hue: var(--ui-surface);
478
478
  }
479
- [data-component~="ui-button"][data-ui-button-state~="tone=danger"][data-v-0c121308],
480
- [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-0c121308] {
479
+ [data-component~="ui-button"][data-ui-button-state~="tone=danger"][data-v-97872575],
480
+ [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-97872575] {
481
481
  --_hue: var(--ui-danger);
482
482
  --_hue-hover: var(--ui-danger-hover);
483
483
  --_hue-active: var(--ui-danger-hover);
484
484
  --_hue-text: var(--ui-danger-hover);
485
485
  --_on-hue: var(--ui-on-danger);
486
486
  }
487
- [data-component~="ui-button"][data-ui-button-state~="tone=success"][data-v-0c121308] {
487
+ [data-component~="ui-button"][data-ui-button-state~="tone=success"][data-v-97872575] {
488
488
  --_hue: var(--ui-success);
489
489
  --_hue-hover: color-mix(in srgb, var(--ui-success) 85%, #000);
490
490
  --_hue-active: color-mix(in srgb, var(--ui-success) 75%, #000);
491
491
  --_hue-text: color-mix(in srgb, var(--ui-success) 85%, #000);
492
492
  --_on-hue: var(--ui-surface);
493
493
  }
494
- [data-component~="ui-button"][data-ui-button-state~="tone=warning"][data-v-0c121308] {
494
+ [data-component~="ui-button"][data-ui-button-state~="tone=warning"][data-v-97872575] {
495
495
  --_hue: var(--ui-warning);
496
496
  --_hue-hover: color-mix(in srgb, var(--ui-warning) 85%, #000);
497
497
  --_hue-active: color-mix(in srgb, var(--ui-warning) 75%, #000);
498
498
  --_hue-text: color-mix(in srgb, var(--ui-warning) 85%, #000);
499
499
  --_on-hue: var(--ui-surface);
500
500
  }
501
- [data-component~="ui-button"][data-ui-button-state~="tone=info"][data-v-0c121308] {
501
+ [data-component~="ui-button"][data-ui-button-state~="tone=info"][data-v-97872575] {
502
502
  --_hue: var(--ui-info);
503
503
  --_hue-hover: color-mix(in srgb, var(--ui-info) 85%, #000);
504
504
  --_hue-active: color-mix(in srgb, var(--ui-info) 75%, #000);
505
505
  --_hue-text: color-mix(in srgb, var(--ui-info) 85%, #000);
506
506
  --_on-hue: var(--ui-surface);
507
507
  }
508
- [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-0c121308] {
508
+ [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-97872575] {
509
509
  border-color: transparent;
510
510
  background: transparent;
511
511
  box-shadow: none;
@@ -513,24 +513,24 @@ ol[data-v-0d86d58e] {
513
513
  }
514
514
 
515
515
  /* Tints derive from the text colour, not a surface token, so hover and press show on any background. */
516
- [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-0c121308]:hover:not(:disabled, [aria-disabled="true"]) {
516
+ [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-97872575]:hover:not(:disabled, [aria-disabled="true"]) {
517
517
  background-color: var(--ui-button-ghost-hover-surface, oklch(from var(--_tone) l c h / 10%));
518
518
  border-color: transparent;
519
519
  }
520
- [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-0c121308]:active:not(:disabled, [aria-disabled="true"]) {
520
+ [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-97872575]:active:not(:disabled, [aria-disabled="true"]) {
521
521
  background-color: var(--ui-button-ghost-active-surface, oklch(from var(--_tone) l c h / 16%));
522
522
  border-color: transparent;
523
523
  box-shadow: var(--ui-pressed);
524
524
  }
525
525
 
526
526
  /* A soft halo that transitions in with the other box-shadow changes, layered on the raised shadow. */
527
- [data-component~="ui-button"][data-v-0c121308]:focus-visible {
527
+ [data-component~="ui-button"][data-v-97872575]:focus-visible {
528
528
  outline: none;
529
529
  box-shadow:
530
530
  var(--ui-button-shadow, var(--ui-raised)),
531
531
  var(--ui-focus-halo);
532
532
  }
533
- [data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-0c121308]:focus-visible {
533
+ [data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-97872575]:focus-visible {
534
534
  box-shadow:
535
535
  var(--ui-button-solid-shadow, var(--ui-raised)),
536
536
  var(--ui-focus-halo);
@@ -540,7 +540,7 @@ ol[data-v-0d86d58e] {
540
540
  disabled outline is still an outline and a disabled ghost still has no edge. Intent goes — an
541
541
  unavailable action says "unavailable", not "unavailable, and destructive" — and so do the
542
542
  highlight and shadow, because nothing that cannot be pressed should look raised. */
543
- [data-component~="ui-button"][data-v-0c121308]:is(:disabled, [aria-disabled="true"]) {
543
+ [data-component~="ui-button"][data-v-97872575]:is(:disabled, [aria-disabled="true"]) {
544
544
  /* Derived from the tone itself, not from a separate disabled palette: faded toward the
545
545
  page, which desaturates it at the same time. Toward the page rather than toward white,
546
546
  so a dark theme dims where a light one lightens — the same rule, both schemes. */
@@ -557,7 +557,7 @@ ol[data-v-0d86d58e] {
557
557
  }
558
558
 
559
559
  /* A filled button keeps its fill, faded further so its text stays legible on it. */
560
- :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-0c121308], [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-0c121308]):is(:disabled, [aria-disabled="true"]) {
560
+ :is([data-component~="ui-button"][data-ui-button-state~="variant=solid"][data-v-97872575], [data-component~="ui-button"][data-ui-button-state~="variant=danger"][data-v-97872575]):is(:disabled, [aria-disabled="true"]) {
561
561
  --_tone: color-mix(in oklab, var(--_hue) 34%, var(--ui-surface));
562
562
  }
563
563
 
@@ -565,19 +565,37 @@ ol[data-v-0d86d58e] {
565
565
  it takes a surface rather than reading as plain text. The surface is a wash of the faded tone,
566
566
  the way hover washes the live one, so it stays light in every tone. An opaque mix toward the
567
567
  hue came out a mid-grey slab for neutral, whose hue is the ink: louder than the enabled button. */
568
- [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-0c121308]:is(:disabled, [aria-disabled="true"]) {
568
+ [data-component~="ui-button"][data-ui-button-state~="variant=ghost"][data-v-97872575]:is(:disabled, [aria-disabled="true"]) {
569
569
  background-color: oklch(from var(--_tone) l c h / 14%);
570
570
  border-color: transparent;
571
571
  }
572
572
  @media (pointer: coarse) {
573
- [data-component~="ui-button"][data-v-0c121308] {
573
+ [data-component~="ui-button"][data-v-97872575] {
574
574
  min-block-size: var(--ui-control-min-block-size);
575
575
  }
576
576
  }
577
577
 
578
+ /* Under touch, a link-style button's press lands within the control minimum: an invisible hit
579
+ area, centred on it, like IconButton's. A boxed button grows to the minimum itself (below);
580
+ a link-style one keeps its text size, so a standalone one ("See all" under a list) needs the
581
+ area. Only the link needs it: a hit area on every button would reach over its neighbours. */
582
+ html[data-ui-input-modality="touch"]
583
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575] {
584
+ position: relative;
585
+ }
586
+ html[data-ui-input-modality="touch"]
587
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575]::after {
588
+ position: absolute;
589
+ inset: 50% auto auto 50%;
590
+ inline-size: max(100%, var(--ui-control-min-block-size));
591
+ block-size: max(100%, var(--ui-control-min-block-size));
592
+ transform: translate(-50%, -50%);
593
+ content: "";
594
+ }
595
+
578
596
  /* Link: an inline text action. No box, padding, or minimum height (inline targets are exempt under
579
597
  WCAG 2.5.8); the inherited font; an underline that strengthens on hover; a visible focus ring. */
580
- [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-0c121308] {
598
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575] {
581
599
  display: inline;
582
600
  min-block-size: 0;
583
601
  padding: 0;
@@ -595,22 +613,22 @@ ol[data-v-0d86d58e] {
595
613
  color var(--ui-motion-fast) var(--ui-motion-ease),
596
614
  text-decoration-color var(--ui-motion-fast) var(--ui-motion-ease);
597
615
  }
598
- [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-0c121308]:hover:not(:disabled, [aria-disabled="true"]) {
616
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575]:hover:not(:disabled, [aria-disabled="true"]) {
599
617
  color: var(--ui-button-link-hover-text, var(--ui-text-primary));
600
618
  text-decoration-color: currentColor;
601
619
  background: none;
602
620
  transform: none;
603
621
  }
604
- [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-0c121308]:active:not(:disabled, [aria-disabled="true"]) {
622
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575]:active:not(:disabled, [aria-disabled="true"]) {
605
623
  background: none;
606
624
  transform: none;
607
625
  }
608
- [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-0c121308]:is(:disabled, [aria-disabled="true"]) {
626
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575]:is(:disabled, [aria-disabled="true"]) {
609
627
  background: none;
610
628
  border-color: transparent;
611
629
  color: var(--ui-button-disabled-text, var(--ui-disabled-text));
612
630
  }
613
- [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-0c121308]:focus-visible {
631
+ [data-component~="ui-button"][data-ui-button-state~="variant=link"][data-v-97872575]:focus-visible {
614
632
  box-shadow: none;
615
633
  /* Fallback keeps the ring if the token is missing: an unresolved var() would void the outline. */
616
634
  outline: 2px solid var(--ui-focus-ring);
@@ -618,7 +636,7 @@ ol[data-v-0d86d58e] {
618
636
  }
619
637
 
620
638
  /* A component that sets its display still honours the hidden attribute on its root. */
621
- [data-component~="ui-button"][hidden][data-v-0c121308] {
639
+ [data-component~="ui-button"][hidden][data-v-97872575] {
622
640
  display: none;
623
641
  }
624
642