@threadlabs/looma 0.39.0 → 0.39.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.
package/vue/UiButton.vue CHANGED
@@ -904,10 +904,10 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
904
904
  v-if="checkedProps.loading || checkedProps.pending"
905
905
  class="spinner-wrap"
906
906
  data-hn-ui-button
907
- ><UiSpinner class="ui-spinner" size="sm" /></span>{{ ' ' }}<slot />{{ ' ' }}<span
908
- class="badge"
907
+ ><UiSpinner class="ui-spinner" size="sm" /></span>{{ ' ' }}<span
908
+ class="label"
909
909
  data-hn-ui-button
910
- ><slot name="badge" /></span></a>
910
+ ><slot /></span>{{ ' ' }}<span class="badge" data-hn-ui-button><slot name="badge" /></span></a>
911
911
  <button
912
912
  v-else
913
913
  class="ui-button"
@@ -944,10 +944,10 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
944
944
  v-if="checkedProps.loading || checkedProps.pending"
945
945
  class="spinner-wrap"
946
946
  data-hn-ui-button
947
- ><UiSpinner class="ui-spinner" size="sm" /></span>{{ ' ' }}<slot />{{ ' ' }}<span
948
- class="badge"
947
+ ><UiSpinner class="ui-spinner" size="sm" /></span>{{ ' ' }}<span
948
+ class="label"
949
949
  data-hn-ui-button
950
- ><slot name="badge" /></span>
950
+ ><slot /></span>{{ ' ' }}<span class="badge" data-hn-ui-button><slot name="badge" /></span>
951
951
  </button>
952
952
  </template>
953
953
 
@@ -1031,6 +1031,8 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1031
1031
  /* A count is an adornment, not another line of label text. Keep the standard control height
1032
1032
  with enough inset for a 24px mark; large content can still grow the button naturally. */
1033
1033
 
1034
+ /* Trim the text line itself: an anonymous flex item retains font-metric space in some fonts. */
1035
+
1034
1036
  /* Short numeric and icon actions share a minimum box; large values remain readable. */
1035
1037
 
1036
1038
  /* Card actions inherit Button's palette and behavior; only their shared layout changes.
@@ -1125,6 +1127,7 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1125
1127
 
1126
1128
  :global(:scope:where([data-hn-ui-button])) {
1127
1129
  --_button-square-size: var(--ui-button-min-block-size, var(--ui-control-size-md));
1130
+ box-sizing: border-box !important;
1128
1131
  appearance: none;
1129
1132
  min-block-size: var(--ui-button-min-block-size, var(--ui-control-size-md));
1130
1133
  border-style: solid;
@@ -1166,6 +1169,19 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1166
1169
  :global(:scope:not([data-appearance="link"]):has(.badge:not(:empty)):where([data-hn-ui-button])) {
1167
1170
  padding-block: var(--ui-space-0-5) !important;
1168
1171
  }
1172
+ :global(.label:where([data-hn-ui-button])) {
1173
+ display: block !important;
1174
+ align-content: center !important;
1175
+ min-inline-size: 0 !important;
1176
+ min-block-size: 1lh !important;
1177
+ }
1178
+
1179
+ :global(.label:has(svg):where([data-hn-ui-button])) {
1180
+ display: inline-flex !important;
1181
+ align-items: center !important;
1182
+ gap: var(--ui-space-2) !important;
1183
+ text-box-trim: none;
1184
+ }
1169
1185
 
1170
1186
  :global(.badge:where([data-hn-ui-button])) {
1171
1187
  display: inline-flex !important;
@@ -1178,7 +1194,7 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1178
1194
  }
1179
1195
 
1180
1196
  @supports (text-box-trim: trim-both) {
1181
- :global(:scope:where([data-hn-ui-button])) {
1197
+ :global(.label:not(:has(svg)):where([data-hn-ui-button])) {
1182
1198
  text-box-trim: trim-both;
1183
1199
  text-box-edge: cap alphabetic;
1184
1200
  }
@@ -1499,6 +1515,11 @@ useComponentHost(() => import('../components/ui-button/ui-button.js'), {
1499
1515
  text-decoration-color var(--ui-motion-fast) var(--ui-motion-ease);
1500
1516
  }
1501
1517
 
1518
+ :global(:scope[data-appearance="link"] .label:where([data-hn-ui-button])) {
1519
+ display: inline !important;
1520
+ text-box-trim: none;
1521
+ }
1522
+
1502
1523
  :global(:scope[data-appearance="link"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button])) {
1503
1524
  color: var(--ui-button-link-hover-text, var(--ui-text-primary));
1504
1525
  text-decoration-color: currentColor;
@@ -377,20 +377,21 @@ useComponentHost(() => import('../components/ui-checkbox/ui-checkbox.js'), {
377
377
 
378
378
  /* The label, and under it an optional line saying what the choice means. */
379
379
 
380
- /* Centre the tick's box and lift it slightly for the rotated check shape. */
380
+ /* The SVG's painted bounds are centred in its viewBox, including its round stroke.
381
+ Centre that box directly; rotated border boxes do not centre the visible check. */
381
382
 
382
383
  @keyframes ui-checkbox-check {
383
384
  from {
384
385
  opacity: 0;
385
- transform: translateY(calc(var(--_ui-checkbox-size) * -0.09 / 1.125)) rotate(45deg) scale(0.55);
386
+ scale: 0.55;
386
387
  }
387
388
  65% {
388
389
  opacity: 1;
389
- transform: translateY(calc(var(--_ui-checkbox-size) * -0.09 / 1.125)) rotate(45deg) scale(1.12);
390
+ scale: 1.12;
390
391
  }
391
392
  to {
392
393
  opacity: 1;
393
- transform: translateY(calc(var(--_ui-checkbox-size) * -0.09 / 1.125)) rotate(45deg) scale(1);
394
+ scale: 1;
394
395
  }
395
396
  }
396
397
 
@@ -484,7 +485,8 @@ useComponentHost(() => import('../components/ui-checkbox/ui-checkbox.js'), {
484
485
 
485
486
  :global(input:where([data-hn-ui-checkbox])::after) {
486
487
  content: "";
487
- position: absolute;
488
+ position: absolute !important;
489
+ transform: none !important;
488
490
  opacity: 0;
489
491
  transition: opacity var(--ui-motion-fast) var(--ui-motion-ease);
490
492
  }
@@ -497,29 +499,28 @@ useComponentHost(() => import('../components/ui-checkbox/ui-checkbox.js'), {
497
499
  box-shadow: var(--ui-control-inset);
498
500
  }
499
501
  :global(input:checked:where([data-hn-ui-checkbox])::after) {
500
- inset: 0;
501
- margin: auto !important;
502
- inline-size: calc(var(--_ui-checkbox-size) * 0.28 / 1.125);
503
- block-size: calc(var(--_ui-checkbox-size) * 0.5 / 1.125);
504
- /* Longhands, not `border: solid var(...)`: lowering drops a shorthand that omits a
505
- component, which left the tick with no style and no colour. */
506
- border-style: solid;
507
- border-color: var(--ui-text-on-accent);
508
- border-width: 0 calc(var(--_ui-checkbox-size) * 0.125 / 1.125)
509
- calc(var(--_ui-checkbox-size) * 0.125 / 1.125) 0;
502
+ inset: 50% auto auto 50% !important;
503
+ inline-size: calc(var(--_ui-checkbox-size) * 0.7) !important;
504
+ block-size: calc(var(--_ui-checkbox-size) * 0.7) !important;
505
+ background: var(--ui-text-on-accent);
506
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 11.5 5 5 9-9'/%3E%3C/svg%3E")
507
+ center / contain no-repeat;
510
508
  opacity: 1;
511
- transform: translateY(calc(var(--_ui-checkbox-size) * -0.09 / 1.125)) rotate(45deg);
509
+ translate: -50% -50% !important;
512
510
  animation: ui-checkbox-check var(--ui-motion-base)
513
511
  var(--ui-motion-ease-out, cubic-bezier(0.16, 1, 0.3, 1)) both;
514
512
  }
515
513
 
516
514
  :global(input:indeterminate:where([data-hn-ui-checkbox])::after) {
517
- inset: 50% calc(var(--_ui-checkbox-size) * 0.23 / 1.125) auto;
518
- block-size: calc(var(--_ui-checkbox-size) * 0.125 / 1.125);
515
+ mask: none;
516
+ animation: none;
517
+ inset: 50% calc(var(--_ui-checkbox-size) * 0.23 / 1.125) auto !important;
518
+ inline-size: auto !important;
519
+ block-size: calc(var(--_ui-checkbox-size) * 0.125 / 1.125) !important;
519
520
  border-radius: var(--ui-radius-round);
520
521
  background: var(--ui-text-on-accent);
521
522
  opacity: 1;
522
- transform: translateY(-50%);
523
+ translate: 0 -50% !important;
523
524
  }
524
525
 
525
526
  @media (prefers-reduced-motion: reduce) {
@@ -529,6 +530,20 @@ useComponentHost(() => import('../components/ui-checkbox/ui-checkbox.js'), {
529
530
  }
530
531
  }
531
532
 
533
+ @media (forced-colors: active) {
534
+ :global(input:checked:where([data-hn-ui-checkbox])),
535
+ :global(input:indeterminate:where([data-hn-ui-checkbox])) {
536
+ forced-color-adjust: none;
537
+ background: Highlight;
538
+ border-color: Highlight;
539
+ }
540
+ :global(input:checked:where([data-hn-ui-checkbox])::after),
541
+ :global(input:indeterminate:where([data-hn-ui-checkbox])::after) {
542
+ forced-color-adjust: none;
543
+ background: HighlightText;
544
+ }
545
+ }
546
+
532
547
  :global(input:hover:enabled:where([data-hn-ui-checkbox])) {
533
548
  border-color: var(--ui-accent-solid);
534
549
  }
@@ -23,6 +23,7 @@ import {
23
23
  vPropValidity,
24
24
  vuePropInputs,
25
25
  } from './props'
26
+ import UiDisclosure from './UiDisclosure.vue'
26
27
  import UiIcon from './UiIcon.vue'
27
28
  import UiNumberInput from './UiNumberInput.vue'
28
29
 
@@ -262,46 +263,45 @@ useComponentHost(() => import('../components/ui-light-editor/ui-light-editor.js'
262
263
  class="ui-icon"
263
264
  name="lightbulb"
264
265
  /></span>
265
- </button></span></span>{{ ' ' }}<span
266
- class="coordinates"
267
- data-hn-ui-light-editor
268
- ><UiNumberInput
269
- class="ui-number-input"
270
- data-coordinate="x"
271
- :min="0"
272
- :max="100"
273
- :step="1"
274
- unit="%"
275
- label="Light horizontal position"
276
- :value="horizontal"
277
- :size="checkedProps.size"
278
- :disabled="checkedProps.disabled"
279
- v-bind="{
280
- [BINDING_INPUTS_PROP]: {
281
- size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
282
- disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
283
- },
284
- }"
285
- />{{ ' ' }}<UiNumberInput
286
- class="ui-number-input"
287
- data-coordinate="y"
288
- :min="0"
289
- :max="100"
290
- :step="1"
291
- unit="%"
292
- label="Light vertical position"
293
- :value="vertical"
294
- :size="checkedProps.size"
295
- :disabled="checkedProps.disabled"
296
- v-bind="{
297
- [BINDING_INPUTS_PROP]: {
298
- size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
299
- disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
300
- },
301
- }"
302
- /></span>{{ ' ' }}<span class="hint" data-hn-ui-light-editor
303
- >Drag the light, tap the background, use arrow keys, or enter its position. Escape cancels a
304
- drag. Top centre is 50%, 0%.</span></span>
266
+ </button></span></span>{{ ' ' }}<span class="hint" data-hn-ui-light-editor
267
+ >Drag or tap to move the light. Arrow keys adjust; Escape cancels.</span>{{ ' ' }}<UiDisclosure
268
+ class="ui-disclosure"
269
+ summary="Exact position"
270
+ ><span class="coordinates" data-slotted="ui-light-editor" data-hn-ui-light-editor><UiNumberInput
271
+ class="ui-number-input"
272
+ data-coordinate="x"
273
+ :min="0"
274
+ :max="100"
275
+ :step="1"
276
+ unit="%"
277
+ label="Light horizontal position"
278
+ :value="horizontal"
279
+ :size="checkedProps.size"
280
+ :disabled="checkedProps.disabled"
281
+ v-bind="{
282
+ [BINDING_INPUTS_PROP]: {
283
+ size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
284
+ disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
285
+ },
286
+ }"
287
+ />{{ ' ' }}<UiNumberInput
288
+ class="ui-number-input"
289
+ data-coordinate="y"
290
+ :min="0"
291
+ :max="100"
292
+ :step="1"
293
+ unit="%"
294
+ label="Light vertical position"
295
+ :value="vertical"
296
+ :size="checkedProps.size"
297
+ :disabled="checkedProps.disabled"
298
+ v-bind="{
299
+ [BINDING_INPUTS_PROP]: {
300
+ size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
301
+ disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
302
+ },
303
+ }"
304
+ /></span></UiDisclosure></span>
305
305
  </template>
306
306
 
307
307
  <style scoped>
@@ -418,4 +418,120 @@ useComponentHost(() => import('../components/ui-light-editor/ui-light-editor.js'
418
418
  }
419
419
  }
420
420
  }
421
+ @scope ([data-slotted~="ui-light-editor"]:not([data-hn])) to ([data-hn], [data-slotted]) {
422
+ :global(:where(.ui-light-editor):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-light-editor"]))):where([data-hn-ui-light-editor])) {
423
+ display: grid !important;
424
+ gap: var(--ui-space-3) !important;
425
+ min-inline-size: 0;
426
+ padding: 0 !important;
427
+ margin: 0 !important;
428
+ }
429
+ :global(.stage:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
430
+ box-sizing: border-box !important;
431
+ display: block !important;
432
+ block-size: 13rem;
433
+ padding: calc(var(--ui-control-min-block-size) / 2) !important;
434
+ border: var(--ui-border-width) solid var(--ui-control-border);
435
+ border-radius: var(--ui-field-radius, var(--ui-radius-md));
436
+ background: var(--ui-neutral-surface, var(--ui-surface));
437
+ }
438
+ :global(.plane:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
439
+ position: relative;
440
+ display: block !important;
441
+ inline-size: 100%;
442
+ block-size: 100%;
443
+ }
444
+ :global(svg:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
445
+ inline-size: 100%;
446
+ block-size: 100%;
447
+ overflow: visible;
448
+ }
449
+ :global(path:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
450
+ fill: none;
451
+ stroke: var(--ui-border);
452
+ stroke-width: 1;
453
+ vector-effect: non-scaling-stroke;
454
+ }
455
+ :global(.specimen:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
456
+ position: absolute;
457
+ inset: 0;
458
+ display: grid !important;
459
+ place-items: center !important;
460
+ }
461
+ :global(.source:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
462
+ position: absolute;
463
+ left: 50%;
464
+ top: 0;
465
+ translate: -50% -50%;
466
+ display: grid !important;
467
+ place-items: center !important;
468
+ inline-size: max(2rem, var(--ui-control-min-block-size));
469
+ block-size: max(2rem, var(--ui-control-min-block-size));
470
+ padding: 0 !important;
471
+ margin: 0 !important;
472
+ border: 0;
473
+ border-radius: 50%;
474
+ background: transparent;
475
+ cursor: grab;
476
+ touch-action: none;
477
+ }
478
+ :global(.source-glyph:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
479
+ position: relative;
480
+ z-index: 1;
481
+ display: inline-flex !important;
482
+ color: var(--ui-accent);
483
+ font-size: var(--ui-font-size-lg);
484
+ }
485
+ :global(.source:where(:not([data-hn], [data-slotted]:not([data-slotted~="ui-light-editor"]))):where(:scope, :scope
486
+ *):where([data-hn-ui-light-editor])::after) {
487
+ content: "";
488
+ position: absolute;
489
+ inline-size: 2rem;
490
+ block-size: 2rem;
491
+ border: var(--ui-border-width) solid var(--ui-accent);
492
+ border-radius: 50%;
493
+ background: var(--ui-surface-raised);
494
+ box-shadow:
495
+ 0 0 0 var(--ui-space-2) color-mix(in srgb, var(--ui-accent) 12%, transparent),
496
+ var(--ui-shadow-sm);
497
+ }
498
+ :global(.source:active:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
499
+ cursor: grabbing;
500
+ }
501
+ :global(.source:focus-visible:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
502
+ outline: var(--ui-focus-width) solid var(--ui-focus-ring);
503
+ outline-offset: var(--ui-space-1);
504
+ }
505
+ :global(.source:disabled:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
506
+ cursor: not-allowed;
507
+ }
508
+ :global(.source:disabled:where(:not([data-hn], [data-slotted]:not([data-slotted~="ui-light-editor"]))):where(:scope, :scope
509
+ *):where([data-hn-ui-light-editor])::after) {
510
+ background: var(--ui-disabled-surface);
511
+ border-color: var(--ui-disabled-border);
512
+ box-shadow: none;
513
+ }
514
+ :global(.coordinates:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
515
+ display: grid !important;
516
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
517
+ gap: var(--ui-space-2) !important;
518
+ }
519
+ :global(.hint:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
520
+ font-size: var(--ui-font-size-sm);
521
+ color: var(--ui-text-secondary);
522
+ }
523
+ @media (forced-colors: active) {
524
+ :global(.source-glyph:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
525
+ color: CanvasText;
526
+ }
527
+ :global(.source:where(:not([data-hn], [data-slotted]:not([data-slotted~="ui-light-editor"]))):where(:scope, :scope
528
+ *):where([data-hn-ui-light-editor])::after) {
529
+ background: Canvas;
530
+ border-color: CanvasText;
531
+ }
532
+ :global(.source:focus-visible:where(:scope, :scope *):where([data-hn-ui-light-editor])) {
533
+ outline-color: Highlight;
534
+ }
535
+ }
536
+ }
421
537
  </style>
@@ -1,13 +1,20 @@
1
1
  <!-- Generated by HTML Next 1.0.0-alpha.69 for Vue 3.5. Do not edit. -->
2
2
  <script setup lang="ts">
3
- import { computed, watchSyncEffect } from 'vue'
3
+ import { computed, getCurrentInstance, ref, watchSyncEffect } from 'vue'
4
4
  import type { PropType } from 'vue'
5
- import { checkHydratedRoot, nativeAttrs, useReflectedProp } from './host'
5
+ import {
6
+ checkHydratedRoot,
7
+ createDispatch,
8
+ nativeAttrs,
9
+ useComponentHost,
10
+ useReflectedProp,
11
+ } from './host'
6
12
  import {
7
13
  BINDING_INPUTS_PROP,
8
14
  checkedProp,
9
15
  checkPropInput,
10
16
  type InputBindings,
17
+ propValidityState,
11
18
  READY_INPUT,
12
19
  requireInputStatus,
13
20
  UNRESOLVED_INPUT,
@@ -24,8 +31,8 @@ const propValidityContract = {
24
31
  required: false,
25
32
  target: { attribute: 'animated' },
26
33
  description:
27
- 'Gently pulses the placeholder. Off by default, and always still when the reader requests reduced motion.',
28
- default: false,
34
+ 'Moves a subtle highlight from left to right. On by default; pass false to keep it static. Reduced-motion preferences always disable the shimmer.',
35
+ default: true,
29
36
  },
30
37
  height: {
31
38
  type: { kind: 'terminal', name: 'string' },
@@ -62,13 +69,13 @@ const props = defineProps({
62
69
  [BINDING_INPUTS_PROP]: { type: null as unknown as PropType<InputBindings> },
63
70
  })
64
71
  const acceptedProps: Record<string, unknown> = {
65
- animated: false,
72
+ animated: true,
66
73
  height: '',
67
74
  shape: 'text',
68
75
  width: '',
69
76
  }
70
77
  const inputTracking = vuePropInputs(acceptedProps, {
71
- animated: false,
78
+ animated: true,
72
79
  height: '',
73
80
  shape: 'text',
74
81
  width: '',
@@ -124,7 +131,9 @@ watchSyncEffect(() => {
124
131
  void checkedProps.value
125
132
  })
126
133
  const reflectedProp = useReflectedProp()
134
+ const hydrationInstance = getCurrentInstance()
127
135
 
136
+ const root = ref<HTMLElement | null>(null)
128
137
  checkHydratedRoot('span', 'ui-skeleton')
129
138
 
130
139
  /** The values the styles' :host() and :state() rules test. */
@@ -135,6 +144,31 @@ const hostState = computed(() =>
135
144
  checkedProps.value.animated && 'animated',
136
145
  ].filter(Boolean).join(' ')
137
146
  )
147
+
148
+ const dispatch = createDispatch(root)
149
+
150
+ useComponentHost(() => import('../components/ui-skeleton/ui-skeleton.js'), {
151
+ root,
152
+ module: true,
153
+ dispatch,
154
+ controllerSource: {
155
+ specifier: '../components/ui-skeleton/ui-skeleton.js',
156
+ definition: './components/ui-skeleton/ui-skeleton.html',
157
+ },
158
+ props: checkedProps,
159
+ inputs: propInputs,
160
+ inputTracking,
161
+ propInputs: (name: string) => {
162
+ const incoming = hydrationInstance?.vnode.props
163
+ const kebab = name.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase())
164
+ return incoming !== null && incoming !== undefined
165
+ ? (incoming[name] ?? incoming[kebab] ?? null)
166
+ : null
167
+ },
168
+ propNames: ['animated', 'height', 'shape', 'width'],
169
+ propValidity: (name: string) =>
170
+ propValidityState({ contract: propValidityContract, values: { ...props } }, name),
171
+ })
138
172
  </script>
139
173
 
140
174
  <template>
@@ -153,6 +187,7 @@ const hostState = computed(() =>
153
187
  :data-ui-skeleton-prop-shape="reflectedProp('shape', 'shape', checkedProps.shape, undefined, false)"
154
188
  :data-ui-skeleton-prop-width="reflectedProp('width', 'width', checkedProps.width, undefined, false)"
155
189
  :data-ui-skeleton-state="hostState || undefined"
190
+ ref="root"
156
191
  ></span>
157
192
  </template>
158
193
 
@@ -166,13 +201,26 @@ const hostState = computed(() =>
166
201
  syntax: "*";
167
202
  inherits: false;
168
203
  }
169
- @keyframes ui-skeleton-pulse {
170
- 50% {
171
- opacity: 0.45;
204
+ @property --_ui-skeleton-viewport-x {
205
+ syntax: "<length>";
206
+ inherits: false;
207
+ initial-value: 0px;
208
+ }
209
+ @property --_ui-skeleton-viewport-scale {
210
+ syntax: "<number>";
211
+ inherits: false;
212
+ initial-value: 1;
213
+ }
214
+ @keyframes ui-skeleton-shimmer {
215
+ to {
216
+ background-position: calc(100vw / var(--_ui-skeleton-paint-scale) - var(--_ui-skeleton-paint-x))
217
+ 0;
172
218
  }
173
219
  }
174
220
  @scope (.ui-skeleton) to ([data-hn]) {
175
221
  :global(:scope) {
222
+ --_ui-skeleton-paint-x: var(--_ui-skeleton-viewport-x);
223
+ --_ui-skeleton-paint-scale: var(--_ui-skeleton-viewport-scale);
176
224
  display: block !important;
177
225
  position: relative;
178
226
  box-sizing: border-box !important;
@@ -214,18 +262,31 @@ const hostState = computed(() =>
214
262
  }
215
263
 
216
264
  :global(:scope[data-ui-skeleton-state~="animated"]::before) {
217
- animation: ui-skeleton-pulse 1.6s ease-in-out infinite;
265
+ background-image: linear-gradient(
266
+ 90deg,
267
+ transparent,
268
+ light-dark(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.14)) 50%,
269
+ transparent
270
+ );
271
+ background-size: calc(100vw / var(--_ui-skeleton-paint-scale)) 100%;
272
+ background-position: calc(0vw - var(--_ui-skeleton-paint-x)) 0;
273
+ background-repeat: repeat-x;
274
+ animation: ui-skeleton-shimmer 3s linear infinite;
218
275
  }
219
276
  @media (prefers-reduced-motion: reduce) {
220
277
  :global(:scope[data-ui-skeleton-state~="animated"]::before) {
221
278
  animation: none;
279
+ background-image: none;
222
280
  }
223
281
  }
224
282
  @media (forced-colors: active) {
225
283
  :global(:scope::before) {
226
284
  background: CanvasText;
227
285
  opacity: 0.2;
286
+ }
287
+ :global(:scope[data-ui-skeleton-state~="animated"]::before) {
228
288
  animation: none;
289
+ background-image: none;
229
290
  }
230
291
  }
231
292
  :global(:scope[hidden]) {
@@ -113,10 +113,14 @@ var _hoisted_10 = {
113
113
  "data-hn-ui-button": ""
114
114
  };
115
115
  var _hoisted_11 = {
116
+ class: "label",
117
+ "data-hn-ui-button": ""
118
+ };
119
+ var _hoisted_12 = {
116
120
  class: "badge",
117
121
  "data-hn-ui-button": ""
118
122
  };
119
- var _hoisted_12 = [
123
+ var _hoisted_13 = [
120
124
  "data-appearance",
121
125
  "data-tone",
122
126
  "type",
@@ -141,12 +145,16 @@ var _hoisted_12 = [
141
145
  "data-ui-button-prop-variant",
142
146
  "data-ui-button-state"
143
147
  ];
144
- var _hoisted_13 = {
148
+ var _hoisted_14 = {
145
149
  key: 0,
146
150
  class: "spinner-wrap",
147
151
  "data-hn-ui-button": ""
148
152
  };
149
- var _hoisted_14 = {
153
+ var _hoisted_15 = {
154
+ class: "label",
155
+ "data-hn-ui-button": ""
156
+ };
157
+ var _hoisted_16 = {
150
158
  class: "badge",
151
159
  "data-hn-ui-button": ""
152
160
  };
@@ -843,9 +851,9 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
843
851
  size: "sm"
844
852
  })])) : createCommentVNode("v-if", true),
845
853
  _cache[4] || (_cache[4] = createTextVNode(toDisplayString(" "), -1)),
846
- renderSlot(_ctx.$slots, "default", {}, void 0, true),
854
+ createElementVNode("span", _hoisted_11, [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
847
855
  _cache[5] || (_cache[5] = createTextVNode(toDisplayString(" "), -1)),
848
- createElementVNode("span", _hoisted_11, [renderSlot(_ctx.$slots, "badge", {}, void 0, true)])
856
+ createElementVNode("span", _hoisted_12, [renderSlot(_ctx.$slots, "badge", {}, void 0, true)])
849
857
  ], 16, _hoisted_9)), [[unref(vPropValidity), {
850
858
  contract: propValidityContract,
851
859
  values: { ...props }
@@ -880,20 +888,20 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
880
888
  "data-ui-button-state": hostState.value || void 0,
881
889
  ref: "@html-next/root"
882
890
  }), [
883
- checkedProps.value.loading || checkedProps.value.pending ? (openBlock(), createElementBlock("span", _hoisted_13, [createVNode(UiSpinner_default, {
891
+ checkedProps.value.loading || checkedProps.value.pending ? (openBlock(), createElementBlock("span", _hoisted_14, [createVNode(UiSpinner_default, {
884
892
  class: "ui-spinner",
885
893
  size: "sm"
886
894
  })])) : createCommentVNode("v-if", true),
887
895
  _cache[6] || (_cache[6] = createTextVNode(toDisplayString(" "), -1)),
888
- renderSlot(_ctx.$slots, "default", {}, void 0, true),
896
+ createElementVNode("span", _hoisted_15, [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
889
897
  _cache[7] || (_cache[7] = createTextVNode(toDisplayString(" "), -1)),
890
- createElementVNode("span", _hoisted_14, [renderSlot(_ctx.$slots, "badge", {}, void 0, true)])
891
- ], 16, _hoisted_12)), [[unref(vPropValidity), {
898
+ createElementVNode("span", _hoisted_16, [renderSlot(_ctx.$slots, "badge", {}, void 0, true)])
899
+ ], 16, _hoisted_13)), [[unref(vPropValidity), {
892
900
  contract: propValidityContract,
893
901
  values: { ...props }
894
902
  }]]);
895
903
  };
896
904
  }
897
- }), [["__scopeId", "data-v-1eb598b9"]]);
905
+ }), [["__scopeId", "data-v-290745d7"]]);
898
906
  //#endregion
899
907
  export { UiButton_default as t };
@@ -356,6 +356,6 @@ var UiCheckbox_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
356
356
  }]]);
357
357
  };
358
358
  }
359
- }), [["__scopeId", "data-v-d551a32f"]]);
359
+ }), [["__scopeId", "data-v-570a9f0b"]]);
360
360
  //#endregion
361
361
  export { UiCheckbox_default as t };