@lyeve-labs/ui-kit 0.27.0 → 0.29.0
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/dist/components/Banner.svelte +38 -1
- package/dist/components/Banner.svelte.d.ts +9 -0
- package/dist/components/Logo.svelte +20 -15
- package/dist/components/Logo.svelte.d.ts +5 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/styles/theme.css +41 -0
- package/package.json +1 -1
- package/src/lib/styles/theme.css +41 -0
|
@@ -3,9 +3,25 @@
|
|
|
3
3
|
import { HIT_AREA } from '../internal/touch.js';
|
|
4
4
|
import type { Snippet } from 'svelte';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* How long a confirmation holds before it clears itself. The same five
|
|
8
|
+
* seconds Alert waits, because a reader crossing between the two surfaces
|
|
9
|
+
* should not have to learn two timings.
|
|
10
|
+
*/
|
|
11
|
+
const DISMISS_AFTER = 5000;
|
|
12
|
+
|
|
6
13
|
interface Props {
|
|
7
14
|
tone?: StatusToneInput;
|
|
8
15
|
dismissible?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Milliseconds before the banner closes itself, or `true` for the default.
|
|
18
|
+
*
|
|
19
|
+
* A confirmation clears itself. A warning and a failure stay until
|
|
20
|
+
* dismissed, so this is off by default. Pass it wherever the banner
|
|
21
|
+
* reports the outcome of a submit; leave it off where it states a standing
|
|
22
|
+
* condition, which does not stop being true after five seconds.
|
|
23
|
+
*/
|
|
24
|
+
autoDismiss?: number | boolean;
|
|
9
25
|
ondismiss?: () => void;
|
|
10
26
|
class?: string;
|
|
11
27
|
children: Snippet;
|
|
@@ -15,6 +31,7 @@
|
|
|
15
31
|
let {
|
|
16
32
|
tone = 'brand',
|
|
17
33
|
dismissible = false,
|
|
34
|
+
autoDismiss = false,
|
|
18
35
|
ondismiss = undefined,
|
|
19
36
|
class: cls = '',
|
|
20
37
|
children,
|
|
@@ -22,12 +39,25 @@
|
|
|
22
39
|
}: Props = $props();
|
|
23
40
|
|
|
24
41
|
let visible = $state(true);
|
|
42
|
+
/** The pointer is over the banner, or focus is inside it. */
|
|
43
|
+
let held = $state(false);
|
|
25
44
|
|
|
26
45
|
function dismiss() {
|
|
27
46
|
visible = false;
|
|
28
47
|
ondismiss?.();
|
|
29
48
|
}
|
|
30
49
|
|
|
50
|
+
const delay = $derived(autoDismiss === true ? DISMISS_AFTER : Number(autoDismiss) || 0);
|
|
51
|
+
|
|
52
|
+
/** A banner that can close itself can also be closed by hand. */
|
|
53
|
+
const closable = $derived(dismissible || delay > 0);
|
|
54
|
+
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (!visible || held || delay <= 0) return;
|
|
57
|
+
const timer = setTimeout(dismiss, delay);
|
|
58
|
+
return () => clearTimeout(timer);
|
|
59
|
+
});
|
|
60
|
+
|
|
31
61
|
const tones: Record<StatusTone, string> = {
|
|
32
62
|
neutral: 'bg-surface-2 border-line',
|
|
33
63
|
brand: 'bg-brand/10 border-brand/20',
|
|
@@ -40,9 +70,16 @@
|
|
|
40
70
|
</script>
|
|
41
71
|
|
|
42
72
|
{#if visible}
|
|
73
|
+
<!-- The timer stops while the pointer is over the banner or focus is inside
|
|
74
|
+
it, and starts again when they leave. Text is never pulled away from
|
|
75
|
+
somebody reading it. -->
|
|
43
76
|
<div
|
|
44
77
|
role="status"
|
|
45
78
|
class="relative flex items-center gap-3 border-b px-4 py-3 text-sm {tones[t]} {cls}"
|
|
79
|
+
onmouseenter={closable ? () => (held = true) : undefined}
|
|
80
|
+
onmouseleave={closable ? () => (held = false) : undefined}
|
|
81
|
+
onfocusin={closable ? () => (held = true) : undefined}
|
|
82
|
+
onfocusout={closable ? () => (held = false) : undefined}
|
|
46
83
|
>
|
|
47
84
|
<div class="flex flex-1 items-center justify-center gap-3 text-fg">
|
|
48
85
|
{@render children()}
|
|
@@ -52,7 +89,7 @@
|
|
|
52
89
|
<div class="shrink-0">{@render action()}</div>
|
|
53
90
|
{/if}
|
|
54
91
|
|
|
55
|
-
{#if
|
|
92
|
+
{#if closable}
|
|
56
93
|
<button
|
|
57
94
|
type="button"
|
|
58
95
|
onclick={dismiss}
|
|
@@ -3,6 +3,15 @@ import type { Snippet } from 'svelte';
|
|
|
3
3
|
interface Props {
|
|
4
4
|
tone?: StatusToneInput;
|
|
5
5
|
dismissible?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Milliseconds before the banner closes itself, or `true` for the default.
|
|
8
|
+
*
|
|
9
|
+
* A confirmation clears itself. A warning and a failure stay until
|
|
10
|
+
* dismissed, so this is off by default. Pass it wherever the banner
|
|
11
|
+
* reports the outcome of a submit; leave it off where it states a standing
|
|
12
|
+
* condition, which does not stop being true after five seconds.
|
|
13
|
+
*/
|
|
14
|
+
autoDismiss?: number | boolean;
|
|
6
15
|
ondismiss?: () => void;
|
|
7
16
|
class?: string;
|
|
8
17
|
children: Snippet;
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
* drew a near-black column on a dark surface. There is no media query here
|
|
12
12
|
* for that reason, and none belongs here.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Every face and the wordmark paint from the mark-* tokens, which carry the
|
|
15
|
+
* brand book's colours per theme: the same lockup the documentation site
|
|
16
|
+
* ships as a static file. They are separate from the brand ramp because that
|
|
17
|
+
* ramp darkens for text contrast in the light theme and inverts the mark's
|
|
18
|
+
* lighting there.
|
|
17
19
|
*/
|
|
18
20
|
|
|
19
21
|
type Size = 'sm' | 'md' | 'lg';
|
|
@@ -47,10 +49,7 @@
|
|
|
47
49
|
const px = $derived(marks[size]);
|
|
48
50
|
</script>
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
in a link that carries no colour of its own, so currentColor would
|
|
52
|
-
otherwise be whatever that ancestor happened to hold. -->
|
|
53
|
-
<span class="inline-flex items-center gap-2 text-fg {klass}">
|
|
52
|
+
<span class="inline-flex items-center gap-2 {klass}">
|
|
54
53
|
<span class="inline-flex shrink-0 items-center justify-center">
|
|
55
54
|
<svg
|
|
56
55
|
width={px}
|
|
@@ -60,18 +59,24 @@
|
|
|
60
59
|
aria-hidden="true"
|
|
61
60
|
>
|
|
62
61
|
<g transform="translate(6 4)">
|
|
63
|
-
<polygon class="fill-
|
|
64
|
-
<polygon class="fill-
|
|
65
|
-
<polygon class="fill-
|
|
66
|
-
<polygon class="fill-
|
|
67
|
-
<polygon class="fill-
|
|
68
|
-
<polygon class="fill-
|
|
69
|
-
<polygon class="fill-
|
|
62
|
+
<polygon class="fill-mark-ink" points="0,14 14,7 14,40 0,47" />
|
|
63
|
+
<polygon class="fill-mark-foot" points="0,47 14,40 14,54 0,61" />
|
|
64
|
+
<polygon class="fill-mark-step" points="14,40 28,33 28,47 14,54" />
|
|
65
|
+
<polygon class="fill-mark-top" points="14,54 28,47 56,33 42,40" />
|
|
66
|
+
<polygon class="fill-mark-side" points="42,40 56,33 56,47 42,54" />
|
|
67
|
+
<polygon class="fill-mark-face" points="14,54 28,61 42,54 28,47" />
|
|
68
|
+
<polygon class="fill-mark-face" points="28,47 42,54 56,47 42,40" />
|
|
70
69
|
</g>
|
|
71
70
|
</svg>
|
|
72
71
|
</span>
|
|
73
72
|
|
|
74
73
|
{#if wordmark}
|
|
75
|
-
|
|
74
|
+
<!-- The accent splits the word across two elements, which some screen
|
|
75
|
+
readers announce letter group by letter group, so the painted word is
|
|
76
|
+
hidden and the name is given once as plain text. -->
|
|
77
|
+
<span class="font-bold tracking-tight text-mark-ink {words[size]}">
|
|
78
|
+
<span aria-hidden="true">Ly<span class="text-mark-accent">E</span>ve</span>
|
|
79
|
+
<span class="sr-only">LyEve</span>
|
|
80
|
+
</span>
|
|
76
81
|
{/if}
|
|
77
82
|
</span>
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
* drew a near-black column on a dark surface. There is no media query here
|
|
11
11
|
* for that reason, and none belongs here.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* Every face and the wordmark paint from the mark-* tokens, which carry the
|
|
14
|
+
* brand book's colours per theme: the same lockup the documentation site
|
|
15
|
+
* ships as a static file. They are separate from the brand ramp because that
|
|
16
|
+
* ramp darkens for text contrast in the light theme and inverts the mark's
|
|
17
|
+
* lighting there.
|
|
16
18
|
*/
|
|
17
19
|
type Size = 'sm' | 'md' | 'lg';
|
|
18
20
|
interface Props {
|
package/dist/index.d.ts
CHANGED
|
@@ -93,4 +93,4 @@ export { cn, type ClassValue } from './utils/cn.js';
|
|
|
93
93
|
export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setTheme, setThemePreference, systemTheme, themeBootScript, toggleTheme, watchSystemTheme, THEME_PREFERENCES, type Theme, type ThemePreference, } from './utils/theme.js';
|
|
94
94
|
export * as motion from './motion.js';
|
|
95
95
|
export type { Rung as MotionRung, Curve as MotionCurve } from './motion.js';
|
|
96
|
-
export declare const VERSION = "0.
|
|
96
|
+
export declare const VERSION = "0.29.0";
|
package/dist/index.js
CHANGED
|
@@ -103,4 +103,4 @@ export * as motion from './motion.js';
|
|
|
103
103
|
// ── Version ────────────────────────────────────────────────────────────────
|
|
104
104
|
// Generated from package.json by `pnpm version:sync`. Bump package.json, never
|
|
105
105
|
// this line; the build and the test suite fail when the two disagree.
|
|
106
|
-
export const VERSION = '0.
|
|
106
|
+
export const VERSION = '0.29.0';
|
package/dist/styles/theme.css
CHANGED
|
@@ -57,6 +57,19 @@
|
|
|
57
57
|
* paints it on and the badge as well. */
|
|
58
58
|
--color-violet: #9587f2;
|
|
59
59
|
|
|
60
|
+
/* The product mark's faces, at the brand book's values. They are their own
|
|
61
|
+
* tokens because the brand ramp above is tuned for text contrast: in the
|
|
62
|
+
* light theme it darkens to #005a77 and brand-light sits below brand, so a
|
|
63
|
+
* mark painted from it inverts its lighting. A logotype is exempt from the
|
|
64
|
+
* contrast floor, so these keep the published colours instead. */
|
|
65
|
+
--color-mark-ink: #ffffff;
|
|
66
|
+
--color-mark-foot: #9aa1ad;
|
|
67
|
+
--color-mark-step: #c5cad3;
|
|
68
|
+
--color-mark-top: #00d4ff;
|
|
69
|
+
--color-mark-side: #0099c4;
|
|
70
|
+
--color-mark-face: #00b4dd;
|
|
71
|
+
--color-mark-accent: #00d4ff;
|
|
72
|
+
|
|
60
73
|
/* #15803d and #b45309 sit at ~3.7:1 on ink, below the 4.5:1 AA floor
|
|
61
74
|
* for the text-size status labels that use them. */
|
|
62
75
|
--color-success: #22c55e;
|
|
@@ -396,12 +409,33 @@ html[data-theme='light'] {
|
|
|
396
409
|
--color-brand-light: #004f69;
|
|
397
410
|
--color-brand-deep: #00455c;
|
|
398
411
|
--color-violet: #5544da;
|
|
412
|
+
--color-mark-ink: #0a0e14;
|
|
413
|
+
--color-mark-foot: #9aa1ad;
|
|
414
|
+
--color-mark-step: #c5cad3;
|
|
415
|
+
--color-mark-top: #0099c4;
|
|
416
|
+
--color-mark-side: #006a8a;
|
|
417
|
+
--color-mark-face: #007ea6;
|
|
418
|
+
--color-mark-accent: #00d4ff;
|
|
399
419
|
|
|
400
420
|
--color-success: #126c34;
|
|
401
421
|
--color-warn: #904207;
|
|
402
422
|
--color-danger: #ab1a1a;
|
|
403
423
|
}
|
|
404
424
|
|
|
425
|
+
/*
|
|
426
|
+
* A forced-colors scheme repaints the page but not a fill named in hex, so the
|
|
427
|
+
* mark's white column vanished on a white high-contrast canvas. Its neutral
|
|
428
|
+
* faces take the system colours there; the cyan faces keep their shape.
|
|
429
|
+
*/
|
|
430
|
+
@media (forced-colors: active) {
|
|
431
|
+
:root,
|
|
432
|
+
html[data-theme='light'] {
|
|
433
|
+
--color-mark-ink: CanvasText;
|
|
434
|
+
--color-mark-foot: GrayText;
|
|
435
|
+
--color-mark-step: GrayText;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
405
439
|
/*
|
|
406
440
|
* The four durations as utilities. A --duration-* token generates nothing
|
|
407
441
|
* (see the motion section of the @theme block), so each is declared here the
|
|
@@ -552,6 +586,13 @@ html[data-theme='light'] {
|
|
|
552
586
|
--color-brand-light: #000000;
|
|
553
587
|
--color-brand-deep: #000000;
|
|
554
588
|
--color-violet: #000000;
|
|
589
|
+
/* The mark keeps its light-theme faces: in black every face is one
|
|
590
|
+
* shape and the L is gone. Printing from the dark theme would otherwise
|
|
591
|
+
* put a white column on white paper. */
|
|
592
|
+
--color-mark-ink: #0a0e14;
|
|
593
|
+
--color-mark-top: #0099c4;
|
|
594
|
+
--color-mark-side: #006a8a;
|
|
595
|
+
--color-mark-face: #007ea6;
|
|
555
596
|
--color-success: #000000;
|
|
556
597
|
--color-warn: #000000;
|
|
557
598
|
--color-danger: #000000;
|
package/package.json
CHANGED
package/src/lib/styles/theme.css
CHANGED
|
@@ -57,6 +57,19 @@
|
|
|
57
57
|
* paints it on and the badge as well. */
|
|
58
58
|
--color-violet: #9587f2;
|
|
59
59
|
|
|
60
|
+
/* The product mark's faces, at the brand book's values. They are their own
|
|
61
|
+
* tokens because the brand ramp above is tuned for text contrast: in the
|
|
62
|
+
* light theme it darkens to #005a77 and brand-light sits below brand, so a
|
|
63
|
+
* mark painted from it inverts its lighting. A logotype is exempt from the
|
|
64
|
+
* contrast floor, so these keep the published colours instead. */
|
|
65
|
+
--color-mark-ink: #ffffff;
|
|
66
|
+
--color-mark-foot: #9aa1ad;
|
|
67
|
+
--color-mark-step: #c5cad3;
|
|
68
|
+
--color-mark-top: #00d4ff;
|
|
69
|
+
--color-mark-side: #0099c4;
|
|
70
|
+
--color-mark-face: #00b4dd;
|
|
71
|
+
--color-mark-accent: #00d4ff;
|
|
72
|
+
|
|
60
73
|
/* #15803d and #b45309 sit at ~3.7:1 on ink, below the 4.5:1 AA floor
|
|
61
74
|
* for the text-size status labels that use them. */
|
|
62
75
|
--color-success: #22c55e;
|
|
@@ -396,12 +409,33 @@ html[data-theme='light'] {
|
|
|
396
409
|
--color-brand-light: #004f69;
|
|
397
410
|
--color-brand-deep: #00455c;
|
|
398
411
|
--color-violet: #5544da;
|
|
412
|
+
--color-mark-ink: #0a0e14;
|
|
413
|
+
--color-mark-foot: #9aa1ad;
|
|
414
|
+
--color-mark-step: #c5cad3;
|
|
415
|
+
--color-mark-top: #0099c4;
|
|
416
|
+
--color-mark-side: #006a8a;
|
|
417
|
+
--color-mark-face: #007ea6;
|
|
418
|
+
--color-mark-accent: #00d4ff;
|
|
399
419
|
|
|
400
420
|
--color-success: #126c34;
|
|
401
421
|
--color-warn: #904207;
|
|
402
422
|
--color-danger: #ab1a1a;
|
|
403
423
|
}
|
|
404
424
|
|
|
425
|
+
/*
|
|
426
|
+
* A forced-colors scheme repaints the page but not a fill named in hex, so the
|
|
427
|
+
* mark's white column vanished on a white high-contrast canvas. Its neutral
|
|
428
|
+
* faces take the system colours there; the cyan faces keep their shape.
|
|
429
|
+
*/
|
|
430
|
+
@media (forced-colors: active) {
|
|
431
|
+
:root,
|
|
432
|
+
html[data-theme='light'] {
|
|
433
|
+
--color-mark-ink: CanvasText;
|
|
434
|
+
--color-mark-foot: GrayText;
|
|
435
|
+
--color-mark-step: GrayText;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
405
439
|
/*
|
|
406
440
|
* The four durations as utilities. A --duration-* token generates nothing
|
|
407
441
|
* (see the motion section of the @theme block), so each is declared here the
|
|
@@ -552,6 +586,13 @@ html[data-theme='light'] {
|
|
|
552
586
|
--color-brand-light: #000000;
|
|
553
587
|
--color-brand-deep: #000000;
|
|
554
588
|
--color-violet: #000000;
|
|
589
|
+
/* The mark keeps its light-theme faces: in black every face is one
|
|
590
|
+
* shape and the L is gone. Printing from the dark theme would otherwise
|
|
591
|
+
* put a white column on white paper. */
|
|
592
|
+
--color-mark-ink: #0a0e14;
|
|
593
|
+
--color-mark-top: #0099c4;
|
|
594
|
+
--color-mark-side: #006a8a;
|
|
595
|
+
--color-mark-face: #007ea6;
|
|
555
596
|
--color-success: #000000;
|
|
556
597
|
--color-warn: #000000;
|
|
557
598
|
--color-danger: #000000;
|