@hyvnt/hyvui 0.2.0 → 0.3.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.
Files changed (86) hide show
  1. package/README.md +264 -253
  2. package/dist/components/ambient/CornerBrackets.svelte +83 -87
  3. package/dist/components/ambient/DataStream.svelte +111 -94
  4. package/dist/components/ambient/GlyphMark.svelte +69 -69
  5. package/dist/components/ambient/GridOverlay.svelte +26 -28
  6. package/dist/components/ambient/ParallaxLayer.svelte +37 -41
  7. package/dist/components/ambient/ScanBand.svelte +95 -91
  8. package/dist/components/ambient/SignalRing.svelte +100 -100
  9. package/dist/components/ambient/ThreadLine.svelte +71 -78
  10. package/dist/components/ambient/Vignette.svelte +24 -26
  11. package/dist/components/depth/DepthLayer.svelte +22 -27
  12. package/dist/components/depth/DepthStage.svelte +63 -62
  13. package/dist/components/depth/FloatCard.svelte +113 -104
  14. package/dist/components/depth/HorizonGrid.svelte +216 -160
  15. package/dist/components/depth/Plinth.svelte +52 -57
  16. package/dist/components/display/Avatar.svelte +64 -69
  17. package/dist/components/display/Badge.svelte +59 -63
  18. package/dist/components/display/Blockquote.svelte +31 -34
  19. package/dist/components/display/CodeBlock.svelte +71 -76
  20. package/dist/components/display/MetricCard.svelte +77 -83
  21. package/dist/components/display/Table.svelte +99 -104
  22. package/dist/components/feedback/Alert.svelte +71 -76
  23. package/dist/components/feedback/EmptyState.svelte +68 -68
  24. package/dist/components/feedback/ErrorState.svelte +73 -73
  25. package/dist/components/feedback/Skeleton.svelte +52 -52
  26. package/dist/components/feedback/StatusDot.svelte +49 -54
  27. package/dist/components/feedback/StatusLine.svelte +122 -122
  28. package/dist/components/feedback/Toast.svelte +130 -136
  29. package/dist/components/inputs/Button.svelte +240 -237
  30. package/dist/components/inputs/Checkbox.svelte +104 -105
  31. package/dist/components/inputs/FileUpload.svelte +165 -163
  32. package/dist/components/inputs/Input.svelte +145 -147
  33. package/dist/components/inputs/Select.svelte +156 -150
  34. package/dist/components/inputs/Textarea.svelte +153 -154
  35. package/dist/components/inputs/Toggle.svelte +120 -120
  36. package/dist/components/layout/Card.svelte +70 -76
  37. package/dist/components/layout/Drawer.svelte +133 -109
  38. package/dist/components/layout/Grid.svelte +118 -43
  39. package/dist/components/layout/Grid.svelte.d.ts +8 -2
  40. package/dist/components/layout/Modal.svelte +176 -159
  41. package/dist/components/layout/Panel.svelte +49 -54
  42. package/dist/components/layout/Popover.svelte +178 -67
  43. package/dist/components/layout/Popover.svelte.d.ts +10 -1
  44. package/dist/components/layout/Stack.svelte +53 -53
  45. package/dist/components/navigation/Breadcrumb.svelte +70 -73
  46. package/dist/components/navigation/DropdownMenu.svelte +167 -124
  47. package/dist/components/navigation/DropdownMenu.svelte.d.ts +12 -2
  48. package/dist/components/navigation/SidebarNav.svelte +86 -90
  49. package/dist/components/navigation/Tabs.svelte +81 -86
  50. package/dist/components/navigation/Topbar.svelte +85 -85
  51. package/dist/components/patterns/ActionBar.svelte +71 -76
  52. package/dist/components/patterns/ConfirmDialog.svelte +63 -64
  53. package/dist/components/patterns/PageHeader.svelte +109 -114
  54. package/dist/components/patterns/SearchBar.svelte +54 -59
  55. package/dist/components/patterns/TerminalBoot.svelte +104 -104
  56. package/dist/components/primitives/Divider.svelte +26 -29
  57. package/dist/components/primitives/Icon.svelte +44 -49
  58. package/dist/components/primitives/Label.svelte +39 -44
  59. package/dist/components/primitives/Surface.svelte +89 -87
  60. package/dist/components/primitives/Text.svelte +98 -98
  61. package/dist/components/scenes/ArchiveScene.svelte +92 -95
  62. package/dist/components/scenes/ArchiveScene.svelte.d.ts +7 -1
  63. package/dist/components/scenes/LogScene.svelte +72 -77
  64. package/dist/components/scenes/NarrativeScene.svelte +91 -92
  65. package/dist/components/scenes/ReadoutScene.svelte +120 -107
  66. package/dist/components/scenes/ReadoutScene.svelte.d.ts +3 -1
  67. package/dist/components/scenes/StageScene.svelte +97 -104
  68. package/dist/examples/FieldReport.svelte +226 -223
  69. package/dist/examples/ObservationDeck.svelte +333 -317
  70. package/dist/examples/SignalLost.svelte +191 -191
  71. package/dist/styles.css +113 -0
  72. package/dist/system/actions/echo.js +9 -9
  73. package/dist/system/actions/resolve.js +9 -9
  74. package/dist/system/actions/reveal.js +1 -1
  75. package/dist/system/actions/surface.js +13 -1
  76. package/dist/system/depth/depth.css +49 -49
  77. package/dist/system/depth/depth.js +1 -1
  78. package/dist/system/expressions.css +80 -80
  79. package/dist/system/override-template.css +72 -72
  80. package/dist/system/register.css +74 -74
  81. package/dist/system/scroll-lock.d.ts +6 -0
  82. package/dist/system/scroll-lock.js +23 -0
  83. package/dist/tokens/tokens.css +100 -86
  84. package/dist/tokens/tokens.js +4 -4
  85. package/dist/utils/motion.js +1 -1
  86. package/package.json +67 -60
@@ -1,76 +1,70 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
- import Surface from '../primitives/Surface.svelte';
4
- import type { Snippet } from 'svelte';
5
-
6
- interface Props {
7
- /** TranslateY offset for staggered card grids. */
8
- staggerOffset?: string;
9
- /** Additional CSS classes. */
10
- class?: string;
11
- /** Card header slot. */
12
- header?: Snippet;
13
- /** Card body content. */
14
- children?: Snippet;
15
- /** Card footer slot. */
16
- footer?: Snippet;
17
- }
18
-
19
- let {
20
- staggerOffset = '',
21
- class: className = '',
22
- header,
23
- children,
24
- footer,
25
- }: Props = $props();
26
-
27
- const style = $derived(staggerOffset ? `transform: translateY(${staggerOffset})` : '');
28
- </script>
29
-
30
- <div class={cn('hyvui-card-wrap', className)} {style}>
31
- <Surface variant="card" class="hyvui-card-inner">
32
- {#if header}
33
- <div class="hyvui-card-header">
34
- {@render header()}
35
- </div>
36
- {/if}
37
- {#if children}
38
- <div class="hyvui-card-body">
39
- {@render children()}
40
- </div>
41
- {/if}
42
- {#if footer}
43
- <div class="hyvui-card-footer">
44
- {@render footer()}
45
- </div>
46
- {/if}
47
- </Surface>
48
- </div>
49
-
50
- <style>
51
- .hyvui-card-wrap {
52
- display: block;
53
- }
54
-
55
- :global(.hyvui-card-inner) {
56
- padding: var(--space-card);
57
- display: flex;
58
- flex-direction: column;
59
- gap: var(--space-lg);
60
- }
61
-
62
- .hyvui-card-header {
63
- padding-bottom: var(--space-sm);
64
- border-bottom: 1px solid color-mix(in srgb, var(--line) 92%, transparent);
65
- }
66
-
67
- .hyvui-card-body {
68
- flex: 1;
69
- min-width: 0;
70
- }
71
-
72
- .hyvui-card-footer {
73
- padding-top: var(--space-sm);
74
- border-top: 1px solid color-mix(in srgb, var(--line) 92%, transparent);
75
- }
76
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import Surface from '../primitives/Surface.svelte';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ interface Props {
7
+ /** TranslateY offset for staggered card grids. */
8
+ staggerOffset?: string;
9
+ /** Additional CSS classes. */
10
+ class?: string;
11
+ /** Card header slot. */
12
+ header?: Snippet;
13
+ /** Card body content. */
14
+ children?: Snippet;
15
+ /** Card footer slot. */
16
+ footer?: Snippet;
17
+ }
18
+
19
+ let { staggerOffset = '', class: className = '', header, children, footer }: Props = $props();
20
+
21
+ const style = $derived(staggerOffset ? `transform: translateY(${staggerOffset})` : '');
22
+ </script>
23
+
24
+ <div class={cn('hyvui-card-wrap', className)} {style}>
25
+ <Surface variant="card" class="hyvui-card-inner">
26
+ {#if header}
27
+ <div class="hyvui-card-header">
28
+ {@render header()}
29
+ </div>
30
+ {/if}
31
+ {#if children}
32
+ <div class="hyvui-card-body">
33
+ {@render children()}
34
+ </div>
35
+ {/if}
36
+ {#if footer}
37
+ <div class="hyvui-card-footer">
38
+ {@render footer()}
39
+ </div>
40
+ {/if}
41
+ </Surface>
42
+ </div>
43
+
44
+ <style>
45
+ .hyvui-card-wrap {
46
+ display: block;
47
+ }
48
+
49
+ :global(.hyvui-card-inner) {
50
+ padding: var(--space-card);
51
+ display: flex;
52
+ flex-direction: column;
53
+ gap: var(--space-lg);
54
+ }
55
+
56
+ .hyvui-card-header {
57
+ padding-bottom: var(--space-sm);
58
+ border-bottom: 1px solid color-mix(in srgb, var(--line) 92%, transparent);
59
+ }
60
+
61
+ .hyvui-card-body {
62
+ flex: 1;
63
+ min-width: 0;
64
+ }
65
+
66
+ .hyvui-card-footer {
67
+ padding-top: var(--space-sm);
68
+ border-top: 1px solid color-mix(in srgb, var(--line) 92%, transparent);
69
+ }
70
+ </style>
@@ -1,109 +1,133 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
- import Surface from '../primitives/Surface.svelte';
4
- import type { Snippet } from 'svelte';
5
-
6
- interface Props {
7
- /** Controls drawer visibility. */
8
- open?: boolean;
9
- /** Side the drawer slides in from. */
10
- side?: 'left' | 'right';
11
- /** Drawer width. */
12
- width?: string;
13
- /** Additional CSS classes. */
14
- class?: string;
15
- /** Drawer content. */
16
- children?: Snippet;
17
- /** Fires when the drawer is dismissed. */
18
- onclose?: () => void;
19
- }
20
-
21
- let {
22
- open = false,
23
- side = 'right',
24
- width = '320px',
25
- class: className = '',
26
- children,
27
- onclose,
28
- }: Props = $props();
29
-
30
- function handleKeydown(e: KeyboardEvent) {
31
- if (e.key === 'Escape') {
32
- onclose?.();
33
- }
34
- }
35
-
36
- function handleBackdropClick() {
37
- onclose?.();
38
- }
39
- </script>
40
-
41
- {#if open}
42
- <!-- svelte-ignore a11y_no_static_element_interactions -->
43
- <div class="hyvui-drawer-backdrop" onclick={handleBackdropClick} onkeydown={handleKeydown}>
44
- <!-- svelte-ignore a11y_no_static_element_interactions -->
45
- <div
46
- class={cn(
47
- 'hyvui-drawer',
48
- side === 'left' ? 'hyvui-drawer-left' : 'hyvui-drawer-right',
49
- className
50
- )}
51
- style:width={width}
52
- onclick={(e) => e.stopPropagation()}
53
- onkeydown={(e) => e.stopPropagation()}
54
- >
55
- <Surface variant="panel" class="hyvui-drawer-surface">
56
- {#if children}{@render children()}{/if}
57
- </Surface>
58
- </div>
59
- </div>
60
- {/if}
61
-
62
- <style>
63
- .hyvui-drawer-backdrop {
64
- position: fixed;
65
- inset: 0;
66
- z-index: var(--z-modal);
67
- background: rgba(0, 0, 0, 0.72);
68
- }
69
-
70
- .hyvui-drawer {
71
- position: fixed;
72
- top: 0;
73
- bottom: 0;
74
- z-index: var(--z-modal);
75
- }
76
-
77
- .hyvui-drawer-left {
78
- left: 0;
79
- animation: drawer-left-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
80
- }
81
-
82
- .hyvui-drawer-right {
83
- right: 0;
84
- animation: drawer-right-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
85
- }
86
-
87
- :global(.hyvui-drawer-surface) {
88
- height: 100%;
89
- padding: var(--space-card);
90
- overflow-y: auto;
91
- }
92
-
93
- @keyframes drawer-left-in {
94
- from { transform: translateX(-100%); }
95
- to { transform: translateX(0); }
96
- }
97
-
98
- @keyframes drawer-right-in {
99
- from { transform: translateX(100%); }
100
- to { transform: translateX(0); }
101
- }
102
-
103
- @media (prefers-reduced-motion: reduce) {
104
- .hyvui-drawer-left,
105
- .hyvui-drawer-right {
106
- animation: none;
107
- }
108
- }
109
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import { lockScroll } from '../../system/scroll-lock.js';
4
+ import Surface from '../primitives/Surface.svelte';
5
+ import type { Snippet } from 'svelte';
6
+
7
+ interface Props {
8
+ /** Controls drawer visibility. */
9
+ open?: boolean;
10
+ /** Side the drawer slides in from. */
11
+ side?: 'left' | 'right';
12
+ /** Drawer width. */
13
+ width?: string;
14
+ /** Additional CSS classes. */
15
+ class?: string;
16
+ /** Drawer content. */
17
+ children?: Snippet;
18
+ /** Fires when the drawer is dismissed. */
19
+ onclose?: () => void;
20
+ }
21
+
22
+ let {
23
+ open = false,
24
+ side = 'right',
25
+ width = '320px',
26
+ class: className = '',
27
+ children,
28
+ onclose
29
+ }: Props = $props();
30
+
31
+ $effect(() => {
32
+ if (!open) return;
33
+ return lockScroll();
34
+ });
35
+
36
+ $effect(() => {
37
+ if (typeof window === 'undefined') return;
38
+ if (!open) return;
39
+
40
+ function onKeydown(e: KeyboardEvent) {
41
+ if (e.key === 'Escape') onclose?.();
42
+ }
43
+
44
+ window.addEventListener('keydown', onKeydown);
45
+ return () => window.removeEventListener('keydown', onKeydown);
46
+ });
47
+
48
+ function handleBackdropClick(e: MouseEvent) {
49
+ // Only close when the backdrop itself was clicked.
50
+ if (e.target !== e.currentTarget) return;
51
+ onclose?.();
52
+ }
53
+ </script>
54
+
55
+ {#if open}
56
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
57
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
58
+ <div class="hyvui-drawer-backdrop" onclick={handleBackdropClick}>
59
+ <div
60
+ class={cn(
61
+ 'hyvui-drawer',
62
+ side === 'left' ? 'hyvui-drawer-left' : 'hyvui-drawer-right',
63
+ className
64
+ )}
65
+ style:--hyvui-drawer-w={width}
66
+ >
67
+ <Surface variant="panel" class="hyvui-drawer-surface">
68
+ {#if children}{@render children()}{/if}
69
+ </Surface>
70
+ </div>
71
+ </div>
72
+ {/if}
73
+
74
+ <style>
75
+ .hyvui-drawer-backdrop {
76
+ position: fixed;
77
+ inset: 0;
78
+ z-index: var(--z-modal);
79
+ background: rgba(0, 0, 0, 0.72);
80
+ }
81
+
82
+ .hyvui-drawer {
83
+ position: fixed;
84
+ top: 0;
85
+ bottom: 0;
86
+ z-index: var(--z-modal);
87
+ inline-size: min(var(--hyvui-drawer-w, 320px), 100dvw);
88
+ max-inline-size: 100dvw;
89
+ }
90
+
91
+ .hyvui-drawer-left {
92
+ left: 0;
93
+ animation: drawer-left-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
94
+ }
95
+
96
+ .hyvui-drawer-right {
97
+ right: 0;
98
+ animation: drawer-right-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
99
+ }
100
+
101
+ :global(.hyvui-drawer-surface) {
102
+ height: 100%;
103
+ padding: calc(var(--space-card) + var(--safe-top)) calc(var(--space-card) + var(--safe-right))
104
+ calc(var(--space-card) + var(--safe-bottom)) calc(var(--space-card) + var(--safe-left));
105
+ overflow-y: auto;
106
+ overscroll-behavior: contain;
107
+ }
108
+
109
+ @keyframes drawer-left-in {
110
+ from {
111
+ transform: translateX(-100%);
112
+ }
113
+ to {
114
+ transform: translateX(0);
115
+ }
116
+ }
117
+
118
+ @keyframes drawer-right-in {
119
+ from {
120
+ transform: translateX(100%);
121
+ }
122
+ to {
123
+ transform: translateX(0);
124
+ }
125
+ }
126
+
127
+ @media (prefers-reduced-motion: reduce) {
128
+ .hyvui-drawer-left,
129
+ .hyvui-drawer-right {
130
+ animation: none;
131
+ }
132
+ }
133
+ </style>
@@ -1,43 +1,118 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
- import type { Snippet } from 'svelte';
4
-
5
- interface Props {
6
- /** Number of columns or a CSS grid-template-columns value. */
7
- cols?: number | string;
8
- /** Gap between grid items. */
9
- gap?: string;
10
- /** HTML tag to render. */
11
- as?: string;
12
- /** Additional CSS classes. */
13
- class?: string;
14
- /** Grid children. */
15
- children?: Snippet;
16
- }
17
-
18
- let {
19
- cols = 1,
20
- gap = 'var(--space-md)',
21
- as = 'div',
22
- class: className = '',
23
- children,
24
- }: Props = $props();
25
-
26
- const gridCols = $derived(typeof cols === 'number' ? `repeat(${cols}, 1fr)` : cols);
27
- </script>
28
-
29
- <svelte:element
30
- this={as}
31
- class={cn('hyvui-grid', className)}
32
- style:grid-template-columns={gridCols}
33
- style:gap={gap}
34
- >
35
- {#if children}{@render children()}{/if}
36
- </svelte:element>
37
-
38
- <style>
39
- .hyvui-grid {
40
- display: grid;
41
- min-width: 0;
42
- }
43
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ interface Props {
6
+ /** Grid mode. `auto` computes columns from container width. */
7
+ mode?: 'auto' | 'template';
8
+ /** CSS grid-template-columns value (used when mode = 'template'). */
9
+ cols?: string | number;
10
+ /** Minimum column width (used when mode = 'auto'). */
11
+ minColWidth?: string;
12
+ /** Maximum number of columns (used when mode = 'auto'). */
13
+ maxCols?: number;
14
+ /** Gap between grid items. */
15
+ gap?: string;
16
+ /** HTML tag to render. */
17
+ as?: string;
18
+ /** Additional CSS classes. */
19
+ class?: string;
20
+ /** Grid children. */
21
+ children?: Snippet;
22
+ }
23
+
24
+ let {
25
+ mode = 'auto',
26
+ cols = 1,
27
+ minColWidth = '16rem',
28
+ maxCols,
29
+ gap = 'var(--space-md)',
30
+ as = 'div',
31
+ class: className = '',
32
+ children
33
+ }: Props = $props();
34
+
35
+ let gridEl: HTMLElement | undefined = $state();
36
+ let gridCols = $state('repeat(1, minmax(0, 1fr))');
37
+
38
+ function readGapPx(el: HTMLElement): number {
39
+ const cs = getComputedStyle(el);
40
+ const raw = cs.columnGap || cs.gap || '0';
41
+ const px = Number.parseFloat(raw);
42
+ return Number.isFinite(px) ? px : 0;
43
+ }
44
+
45
+ function measureWidthPx(el: HTMLElement, width: string): number {
46
+ const probe = document.createElement('div');
47
+ probe.style.position = 'absolute';
48
+ probe.style.visibility = 'hidden';
49
+ probe.style.pointerEvents = 'none';
50
+ probe.style.width = width;
51
+ probe.style.height = '0';
52
+ probe.style.padding = '0';
53
+ probe.style.border = '0';
54
+ el.appendChild(probe);
55
+ const px = probe.getBoundingClientRect().width;
56
+ probe.remove();
57
+ return px > 0 ? px : 0;
58
+ }
59
+
60
+ $effect(() => {
61
+ if (typeof window === 'undefined') return;
62
+ if (!gridEl) return;
63
+ const el = gridEl;
64
+
65
+ if (mode === 'template') {
66
+ gridCols = typeof cols === 'string' ? cols : `repeat(${cols}, minmax(0, 1fr))`;
67
+ return;
68
+ }
69
+
70
+ // Back-compat: if callers pass a numeric `cols` in auto mode, treat it as maxCols.
71
+ const max = maxCols ?? (typeof cols === 'number' ? cols : undefined);
72
+
73
+ let minPx = measureWidthPx(el, minColWidth);
74
+ if (minPx <= 0) minPx = 16 * 16; // fallback: 16rem at 16px root
75
+
76
+ let last = 0;
77
+ const ro = new ResizeObserver((entries) => {
78
+ const entry = entries[0];
79
+ if (!entry) return;
80
+ const width = entry.contentRect.width;
81
+ const gapPx = readGapPx(el);
82
+ const next = Math.max(1, Math.floor((width + gapPx) / (minPx + gapPx)));
83
+ const clamped = max ? Math.min(next, max) : next;
84
+ if (clamped === last) return;
85
+ last = clamped;
86
+ gridCols = `repeat(${clamped}, minmax(0, 1fr))`;
87
+ });
88
+
89
+ ro.observe(el);
90
+
91
+ // Seed with initial measurement.
92
+ const width = el.getBoundingClientRect().width;
93
+ const gapPx = readGapPx(el);
94
+ const next = Math.max(1, Math.floor((width + gapPx) / (minPx + gapPx)));
95
+ last = max ? Math.min(next, max) : next;
96
+ gridCols = `repeat(${last}, minmax(0, 1fr))`;
97
+
98
+ return () => ro.disconnect();
99
+ });
100
+ </script>
101
+
102
+ <svelte:element
103
+ this={as}
104
+ bind:this={gridEl}
105
+ class={cn('hyvui-grid', className)}
106
+ style:--hyv-grid-cols={gridCols}
107
+ style:gap
108
+ >
109
+ {#if children}{@render children()}{/if}
110
+ </svelte:element>
111
+
112
+ <style>
113
+ .hyvui-grid {
114
+ display: grid;
115
+ min-width: 0;
116
+ grid-template-columns: var(--hyv-grid-cols);
117
+ }
118
+ </style>
@@ -1,7 +1,13 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  interface Props {
3
- /** Number of columns or a CSS grid-template-columns value. */
4
- cols?: number | string;
3
+ /** Grid mode. `auto` computes columns from container width. */
4
+ mode?: 'auto' | 'template';
5
+ /** CSS grid-template-columns value (used when mode = 'template'). */
6
+ cols?: string | number;
7
+ /** Minimum column width (used when mode = 'auto'). */
8
+ minColWidth?: string;
9
+ /** Maximum number of columns (used when mode = 'auto'). */
10
+ maxCols?: number;
5
11
  /** Gap between grid items. */
6
12
  gap?: string;
7
13
  /** HTML tag to render. */