@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,67 +1,178 @@
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 popover visibility. */
8
- open?: boolean;
9
- /** Placement relative to anchor. */
10
- placement?: 'top' | 'bottom' | 'left' | 'right';
11
- /** Additional CSS classes. */
12
- class?: string;
13
- /** Popover content. */
14
- children?: Snippet;
15
- }
16
-
17
- let {
18
- open = false,
19
- placement = 'bottom',
20
- class: className = '',
21
- children,
22
- }: Props = $props();
23
-
24
- const placementStyles: Record<string, string> = {
25
- top: 'bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 0.5rem;',
26
- bottom: 'top: 100%; left: 50%; transform: translateX(-50%); margin-top: 0.5rem;',
27
- left: 'right: 100%; top: 50%; transform: translateY(-50%); margin-right: 0.5rem;',
28
- right: 'left: 100%; top: 50%; transform: translateY(-50%); margin-left: 0.5rem;',
29
- };
30
- </script>
31
-
32
- {#if open}
33
- <div class={cn('hyvui-popover', className)} style={placementStyles[placement]}>
34
- <Surface variant="card" class="hyvui-popover-surface">
35
- {#if children}{@render children()}{/if}
36
- </Surface>
37
- </div>
38
- {/if}
39
-
40
- <style>
41
- .hyvui-popover {
42
- position: absolute;
43
- z-index: var(--z-overlay);
44
- animation: popover-in 0.2s cubic-bezier(0.22, 1, 0.36, 1);
45
- }
46
-
47
- :global(.hyvui-popover-surface) {
48
- padding: 0.5rem 0.75rem;
49
- }
50
-
51
- @keyframes popover-in {
52
- from {
53
- opacity: 0;
54
- transform: translateX(-50%) translateY(4px);
55
- }
56
- to {
57
- opacity: 1;
58
- transform: translateX(-50%) translateY(0);
59
- }
60
- }
61
-
62
- @media (prefers-reduced-motion: reduce) {
63
- .hyvui-popover {
64
- animation: none;
65
- }
66
- }
67
- </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
+ import {
6
+ autoUpdate,
7
+ computePosition,
8
+ flip,
9
+ offset as fuiOffset,
10
+ shift,
11
+ size as fuiSize,
12
+ type Placement
13
+ } from '@floating-ui/dom';
14
+
15
+ // In SSR builds, Svelte strips $effect bodies, which can make these imports appear unused to Rollup.
16
+ // Keeping a tiny reference avoids noisy build warnings without changing runtime behavior.
17
+ const _fui = [autoUpdate, computePosition, flip, fuiOffset, shift, fuiSize];
18
+ void _fui;
19
+
20
+ interface Props {
21
+ /** Controls popover visibility. */
22
+ open?: boolean;
23
+ /** Anchor element the popover positions against. */
24
+ anchor?: HTMLElement | null;
25
+ /** Placement relative to anchor. */
26
+ placement?: Placement;
27
+ /** Offset in pixels from the anchor. */
28
+ offset?: number;
29
+ /** When true, move the popover element to document.body on mount. */
30
+ portal?: boolean;
31
+ /** Additional CSS classes. */
32
+ class?: string;
33
+ /** Popover content. */
34
+ children?: Snippet;
35
+ /** Fires when the popover should close (outside click, Escape). */
36
+ onclose?: () => void;
37
+ }
38
+
39
+ let {
40
+ open = false,
41
+ anchor = null,
42
+ placement = 'bottom-start',
43
+ offset = 8,
44
+ portal = true,
45
+ class: className = '',
46
+ children,
47
+ onclose
48
+ }: Props = $props();
49
+
50
+ let popoverEl: HTMLDivElement | undefined = $state();
51
+
52
+ function close() {
53
+ onclose?.();
54
+ }
55
+
56
+ $effect(() => {
57
+ if (typeof document === 'undefined') return;
58
+ if (!portal) return;
59
+ if (!popoverEl) return;
60
+
61
+ // Manual portal: move the floating node to document.body. Svelte 5's event
62
+ // delegation supports this (see internal render.js comment re: portals).
63
+ document.body.appendChild(popoverEl);
64
+
65
+ return () => {
66
+ popoverEl?.remove();
67
+ };
68
+ });
69
+
70
+ $effect(() => {
71
+ if (typeof window === 'undefined') return;
72
+ if (!open) return;
73
+ if (!anchor || !popoverEl) return;
74
+
75
+ const a = anchor;
76
+ const el = popoverEl;
77
+
78
+ function position() {
79
+ computePosition(a, el, {
80
+ placement,
81
+ strategy: 'fixed',
82
+ middleware: [
83
+ fuiOffset(offset),
84
+ flip(),
85
+ shift({ padding: 8 }),
86
+ fuiSize({
87
+ padding: 8,
88
+ apply({ availableWidth, availableHeight, elements }) {
89
+ Object.assign(elements.floating.style, {
90
+ maxWidth: `${Math.max(0, availableWidth)}px`,
91
+ maxHeight: `${Math.max(0, availableHeight)}px`
92
+ });
93
+ }
94
+ })
95
+ ]
96
+ }).then(({ x, y }) => {
97
+ Object.assign(el.style, {
98
+ left: `${x}px`,
99
+ top: `${y}px`
100
+ });
101
+ });
102
+ }
103
+
104
+ position();
105
+
106
+ const stop = autoUpdate(a, el, position);
107
+
108
+ function onPointerDown(e: PointerEvent) {
109
+ const t = e.target as Node | null;
110
+ if (!t) return;
111
+ if (a.contains(t) || el.contains(t)) return;
112
+ close();
113
+ }
114
+
115
+ function onKeyDown(e: KeyboardEvent) {
116
+ if (e.key === 'Escape') close();
117
+ }
118
+
119
+ const pointerOpts: AddEventListenerOptions = { capture: true };
120
+ window.addEventListener('pointerdown', onPointerDown, pointerOpts);
121
+ window.addEventListener('keydown', onKeyDown);
122
+
123
+ return () => {
124
+ stop();
125
+ window.removeEventListener('pointerdown', onPointerDown, pointerOpts);
126
+ window.removeEventListener('keydown', onKeyDown);
127
+ };
128
+ });
129
+ </script>
130
+
131
+ {#if open && anchor}
132
+ <div bind:this={popoverEl} class={cn('hyvui-popover', className)}>
133
+ <Surface variant="card" class="hyvui-popover-surface">
134
+ <div class="hyvui-popover-content">
135
+ {#if children}{@render children()}{/if}
136
+ </div>
137
+ </Surface>
138
+ </div>
139
+ {/if}
140
+
141
+ <style>
142
+ .hyvui-popover {
143
+ position: fixed;
144
+ z-index: var(--z-overlay);
145
+ left: 0;
146
+ top: 0;
147
+ animation: popover-in 0.2s cubic-bezier(0.22, 1, 0.36, 1);
148
+ max-inline-size: min(90dvw, 28rem);
149
+ }
150
+
151
+ :global(.hyvui-popover-surface) {
152
+ padding: 0;
153
+ }
154
+
155
+ .hyvui-popover-content {
156
+ padding: 0.5rem 0.75rem;
157
+ max-block-size: min(60dvh, 32rem);
158
+ overflow: auto;
159
+ overscroll-behavior: contain;
160
+ }
161
+
162
+ @keyframes popover-in {
163
+ from {
164
+ opacity: 0;
165
+ transform: translateY(4px);
166
+ }
167
+ to {
168
+ opacity: 1;
169
+ transform: translateY(0);
170
+ }
171
+ }
172
+
173
+ @media (prefers-reduced-motion: reduce) {
174
+ .hyvui-popover {
175
+ animation: none;
176
+ }
177
+ }
178
+ </style>
@@ -1,13 +1,22 @@
1
1
  import type { Snippet } from 'svelte';
2
+ import { type Placement } from '@floating-ui/dom';
2
3
  interface Props {
3
4
  /** Controls popover visibility. */
4
5
  open?: boolean;
6
+ /** Anchor element the popover positions against. */
7
+ anchor?: HTMLElement | null;
5
8
  /** Placement relative to anchor. */
6
- placement?: 'top' | 'bottom' | 'left' | 'right';
9
+ placement?: Placement;
10
+ /** Offset in pixels from the anchor. */
11
+ offset?: number;
12
+ /** When true, move the popover element to document.body on mount. */
13
+ portal?: boolean;
7
14
  /** Additional CSS classes. */
8
15
  class?: string;
9
16
  /** Popover content. */
10
17
  children?: Snippet;
18
+ /** Fires when the popover should close (outside click, Escape). */
19
+ onclose?: () => void;
11
20
  }
12
21
  declare const Popover: import("svelte").Component<Props, {}, "">;
13
22
  type Popover = ReturnType<typeof Popover>;
@@ -1,53 +1,53 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
- import type { Snippet } from 'svelte';
4
-
5
- interface Props {
6
- /** Stack direction. */
7
- direction?: 'vertical' | 'horizontal';
8
- /** Gap between items (CSS size string). */
9
- gap?: string;
10
- /** CSS align-items value. */
11
- align?: string;
12
- /** CSS justify-content value. */
13
- justify?: string;
14
- /** Enable flex-wrap. */
15
- wrap?: boolean;
16
- /** HTML tag to render. */
17
- as?: string;
18
- /** Additional CSS classes. */
19
- class?: string;
20
- /** Stack children. */
21
- children?: Snippet;
22
- }
23
-
24
- let {
25
- direction = 'vertical',
26
- gap = 'var(--space-md)',
27
- align = 'stretch',
28
- justify = 'flex-start',
29
- wrap = false,
30
- as = 'div',
31
- class: className = '',
32
- children,
33
- }: Props = $props();
34
- </script>
35
-
36
- <svelte:element
37
- this={as}
38
- class={cn('hyvui-stack', className)}
39
- style:flex-direction={direction === 'horizontal' ? 'row' : 'column'}
40
- style:gap={gap}
41
- style:align-items={align}
42
- style:justify-content={justify}
43
- style:flex-wrap={wrap ? 'wrap' : 'nowrap'}
44
- >
45
- {#if children}{@render children()}{/if}
46
- </svelte:element>
47
-
48
- <style>
49
- .hyvui-stack {
50
- display: flex;
51
- min-width: 0;
52
- }
53
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ interface Props {
6
+ /** Stack direction. */
7
+ direction?: 'vertical' | 'horizontal';
8
+ /** Gap between items (CSS size string). */
9
+ gap?: string;
10
+ /** CSS align-items value. */
11
+ align?: string;
12
+ /** CSS justify-content value. */
13
+ justify?: string;
14
+ /** Enable flex-wrap. */
15
+ wrap?: boolean;
16
+ /** HTML tag to render. */
17
+ as?: string;
18
+ /** Additional CSS classes. */
19
+ class?: string;
20
+ /** Stack children. */
21
+ children?: Snippet;
22
+ }
23
+
24
+ let {
25
+ direction = 'vertical',
26
+ gap = 'var(--space-md)',
27
+ align = 'stretch',
28
+ justify = 'flex-start',
29
+ wrap = false,
30
+ as = 'div',
31
+ class: className = '',
32
+ children
33
+ }: Props = $props();
34
+ </script>
35
+
36
+ <svelte:element
37
+ this={as}
38
+ class={cn('hyvui-stack', className)}
39
+ style:flex-direction={direction === 'horizontal' ? 'row' : 'column'}
40
+ style:gap
41
+ style:align-items={align}
42
+ style:justify-content={justify}
43
+ style:flex-wrap={wrap ? 'wrap' : 'nowrap'}
44
+ >
45
+ {#if children}{@render children()}{/if}
46
+ </svelte:element>
47
+
48
+ <style>
49
+ .hyvui-stack {
50
+ display: flex;
51
+ min-width: 0;
52
+ }
53
+ </style>
@@ -1,73 +1,70 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
-
4
- interface BreadcrumbItem {
5
- label: string;
6
- href?: string;
7
- }
8
-
9
- interface Props {
10
- /** Breadcrumb trail items. */
11
- items?: BreadcrumbItem[];
12
- /** Additional CSS classes. */
13
- class?: string;
14
- }
15
-
16
- let {
17
- items = [],
18
- class: className = '',
19
- }: Props = $props();
20
- </script>
21
-
22
- <nav class={cn('hyvui-breadcrumb', className)} aria-label="breadcrumb">
23
- {#each items as item, i}
24
- {#if i > 0}
25
- <span class="hyvui-breadcrumb-sep">/</span>
26
- {/if}
27
- {#if item.href && i < items.length - 1}
28
- <a href={item.href} class="hyvui-breadcrumb-link">{item.label}</a>
29
- {:else}
30
- <span class="hyvui-breadcrumb-current">{item.label}</span>
31
- {/if}
32
- {/each}
33
- </nav>
34
-
35
- <style>
36
- .hyvui-breadcrumb {
37
- display: flex;
38
- align-items: center;
39
- flex-wrap: wrap;
40
- gap: var(--space-xs);
41
- font-family: var(--font-mono);
42
- font-size: 0.68rem;
43
- letter-spacing: 0.16em;
44
- text-transform: uppercase;
45
- min-width: 0;
46
- }
47
-
48
- .hyvui-breadcrumb-sep {
49
- color: var(--muted-strong);
50
- opacity: 0.7;
51
- }
52
-
53
- .hyvui-breadcrumb-link {
54
- color: var(--muted);
55
- text-decoration: none;
56
- transition: color var(--transition-fast);
57
- }
58
-
59
- .hyvui-breadcrumb-link:hover {
60
- color: var(--accent);
61
- }
62
-
63
- .hyvui-breadcrumb-current {
64
- color: var(--text-soft);
65
- white-space: nowrap;
66
- }
67
-
68
- @media (prefers-reduced-motion: reduce) {
69
- .hyvui-breadcrumb-link {
70
- transition: none;
71
- }
72
- }
73
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+
4
+ interface BreadcrumbItem {
5
+ label: string;
6
+ href?: string;
7
+ }
8
+
9
+ interface Props {
10
+ /** Breadcrumb trail items. */
11
+ items?: BreadcrumbItem[];
12
+ /** Additional CSS classes. */
13
+ class?: string;
14
+ }
15
+
16
+ let { items = [], class: className = '' }: Props = $props();
17
+ </script>
18
+
19
+ <nav class={cn('hyvui-breadcrumb', className)} aria-label="breadcrumb">
20
+ {#each items as item, i}
21
+ {#if i > 0}
22
+ <span class="hyvui-breadcrumb-sep">/</span>
23
+ {/if}
24
+ {#if item.href && i < items.length - 1}
25
+ <a href={item.href} class="hyvui-breadcrumb-link">{item.label}</a>
26
+ {:else}
27
+ <span class="hyvui-breadcrumb-current">{item.label}</span>
28
+ {/if}
29
+ {/each}
30
+ </nav>
31
+
32
+ <style>
33
+ .hyvui-breadcrumb {
34
+ display: flex;
35
+ align-items: center;
36
+ flex-wrap: wrap;
37
+ gap: var(--space-xs);
38
+ font-family: var(--font-mono);
39
+ font-size: 0.68rem;
40
+ letter-spacing: 0.16em;
41
+ text-transform: uppercase;
42
+ min-width: 0;
43
+ }
44
+
45
+ .hyvui-breadcrumb-sep {
46
+ color: var(--muted-strong);
47
+ opacity: 0.7;
48
+ }
49
+
50
+ .hyvui-breadcrumb-link {
51
+ color: var(--muted);
52
+ text-decoration: none;
53
+ transition: color var(--transition-fast);
54
+ }
55
+
56
+ .hyvui-breadcrumb-link:hover {
57
+ color: var(--accent);
58
+ }
59
+
60
+ .hyvui-breadcrumb-current {
61
+ color: var(--text-soft);
62
+ white-space: nowrap;
63
+ }
64
+
65
+ @media (prefers-reduced-motion: reduce) {
66
+ .hyvui-breadcrumb-link {
67
+ transition: none;
68
+ }
69
+ }
70
+ </style>