@hyvnt/hyvui 0.2.0 → 0.4.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 (181) hide show
  1. package/README.md +294 -253
  2. package/dist/components/ambient/ArcaneVein.svelte +151 -0
  3. package/dist/components/ambient/ArcaneVein.svelte.d.ts +31 -0
  4. package/dist/components/ambient/BrassFiligree.svelte +109 -0
  5. package/dist/components/ambient/BrassFiligree.svelte.d.ts +20 -0
  6. package/dist/components/ambient/CornerBrackets.svelte +91 -87
  7. package/dist/components/ambient/CornerBrackets.svelte.d.ts +8 -0
  8. package/dist/components/ambient/CrystalShard.svelte +151 -0
  9. package/dist/components/ambient/CrystalShard.svelte.d.ts +19 -0
  10. package/dist/components/ambient/DataStream.svelte +117 -94
  11. package/dist/components/ambient/DataStream.svelte.d.ts +6 -0
  12. package/dist/components/ambient/EnergyArc.svelte +189 -0
  13. package/dist/components/ambient/EnergyArc.svelte.d.ts +32 -0
  14. package/dist/components/ambient/GlyphMark.svelte +75 -69
  15. package/dist/components/ambient/GlyphMark.svelte.d.ts +6 -0
  16. package/dist/components/ambient/GridOverlay.svelte +34 -28
  17. package/dist/components/ambient/GridOverlay.svelte.d.ts +8 -0
  18. package/dist/components/ambient/HexGrid.svelte +119 -0
  19. package/dist/components/ambient/HexGrid.svelte.d.ts +21 -0
  20. package/dist/components/ambient/ParallaxLayer.svelte +45 -41
  21. package/dist/components/ambient/ParallaxLayer.svelte.d.ts +7 -0
  22. package/dist/components/ambient/ScanBand.svelte +103 -91
  23. package/dist/components/ambient/ScanBand.svelte.d.ts +8 -0
  24. package/dist/components/ambient/ShimmerCloud.svelte +180 -0
  25. package/dist/components/ambient/ShimmerCloud.svelte.d.ts +21 -0
  26. package/dist/components/ambient/SignalRing.svelte +106 -100
  27. package/dist/components/ambient/SignalRing.svelte.d.ts +6 -0
  28. package/dist/components/ambient/ThreadLine.svelte +78 -78
  29. package/dist/components/ambient/ThreadLine.svelte.d.ts +7 -0
  30. package/dist/components/ambient/Vignette.svelte +30 -26
  31. package/dist/components/ambient/Vignette.svelte.d.ts +6 -0
  32. package/dist/components/depth/DepthLayer.svelte +30 -27
  33. package/dist/components/depth/DepthLayer.svelte.d.ts +8 -0
  34. package/dist/components/depth/DepthStage.svelte +67 -62
  35. package/dist/components/depth/DepthStage.svelte.d.ts +8 -0
  36. package/dist/components/depth/FloatCard.svelte +129 -104
  37. package/dist/components/depth/FloatCard.svelte.d.ts +8 -0
  38. package/dist/components/depth/HorizonGrid.svelte +241 -160
  39. package/dist/components/depth/HorizonGrid.svelte.d.ts +9 -0
  40. package/dist/components/depth/Plinth.svelte +62 -57
  41. package/dist/components/depth/Plinth.svelte.d.ts +10 -0
  42. package/dist/components/display/Avatar.svelte +69 -69
  43. package/dist/components/display/Avatar.svelte.d.ts +5 -0
  44. package/dist/components/display/Badge.svelte +75 -63
  45. package/dist/components/display/Badge.svelte.d.ts +6 -0
  46. package/dist/components/display/Blockquote.svelte +35 -34
  47. package/dist/components/display/Blockquote.svelte.d.ts +4 -0
  48. package/dist/components/display/CodeBlock.svelte +76 -76
  49. package/dist/components/display/CodeBlock.svelte.d.ts +5 -0
  50. package/dist/components/display/MetricCard.svelte +100 -83
  51. package/dist/components/display/MetricCard.svelte.d.ts +6 -0
  52. package/dist/components/display/Table.svelte +106 -104
  53. package/dist/components/display/Table.svelte.d.ts +7 -0
  54. package/dist/components/feedback/Alert.svelte +95 -76
  55. package/dist/components/feedback/Alert.svelte.d.ts +6 -0
  56. package/dist/components/feedback/EmptyState.svelte +75 -68
  57. package/dist/components/feedback/EmptyState.svelte.d.ts +7 -0
  58. package/dist/components/feedback/ErrorState.svelte +78 -73
  59. package/dist/components/feedback/ErrorState.svelte.d.ts +5 -0
  60. package/dist/components/feedback/Skeleton.svelte +58 -52
  61. package/dist/components/feedback/Skeleton.svelte.d.ts +6 -0
  62. package/dist/components/feedback/StatusDot.svelte +84 -54
  63. package/dist/components/feedback/StatusDot.svelte.d.ts +6 -0
  64. package/dist/components/feedback/StatusLine.svelte +128 -122
  65. package/dist/components/feedback/StatusLine.svelte.d.ts +6 -0
  66. package/dist/components/feedback/Toast.svelte +144 -136
  67. package/dist/components/feedback/Toast.svelte.d.ts +10 -0
  68. package/dist/components/inputs/Button.svelte +310 -237
  69. package/dist/components/inputs/Button.svelte.d.ts +8 -0
  70. package/dist/components/inputs/Checkbox.svelte +109 -105
  71. package/dist/components/inputs/Checkbox.svelte.d.ts +5 -0
  72. package/dist/components/inputs/FileUpload.svelte +170 -163
  73. package/dist/components/inputs/FileUpload.svelte.d.ts +5 -0
  74. package/dist/components/inputs/Input.svelte +153 -147
  75. package/dist/components/inputs/Input.svelte.d.ts +7 -0
  76. package/dist/components/inputs/Select.svelte +164 -150
  77. package/dist/components/inputs/Select.svelte.d.ts +8 -0
  78. package/dist/components/inputs/Textarea.svelte +160 -154
  79. package/dist/components/inputs/Textarea.svelte.d.ts +6 -0
  80. package/dist/components/inputs/Toggle.svelte +125 -120
  81. package/dist/components/inputs/Toggle.svelte.d.ts +5 -0
  82. package/dist/components/layout/Card.svelte +81 -76
  83. package/dist/components/layout/Card.svelte.d.ts +11 -0
  84. package/dist/components/layout/Drawer.svelte +140 -109
  85. package/dist/components/layout/Drawer.svelte.d.ts +6 -0
  86. package/dist/components/layout/Grid.svelte +128 -43
  87. package/dist/components/layout/Grid.svelte.d.ts +18 -2
  88. package/dist/components/layout/Modal.svelte +191 -159
  89. package/dist/components/layout/Modal.svelte.d.ts +10 -0
  90. package/dist/components/layout/Panel.svelte +58 -54
  91. package/dist/components/layout/Panel.svelte.d.ts +9 -0
  92. package/dist/components/layout/Popover.svelte +188 -67
  93. package/dist/components/layout/Popover.svelte.d.ts +19 -1
  94. package/dist/components/layout/Stack.svelte +65 -53
  95. package/dist/components/layout/Stack.svelte.d.ts +12 -0
  96. package/dist/components/navigation/Breadcrumb.svelte +78 -73
  97. package/dist/components/navigation/Breadcrumb.svelte.d.ts +8 -0
  98. package/dist/components/navigation/DropdownMenu.svelte +179 -124
  99. package/dist/components/navigation/DropdownMenu.svelte.d.ts +24 -2
  100. package/dist/components/navigation/SidebarNav.svelte +96 -90
  101. package/dist/components/navigation/SidebarNav.svelte.d.ts +9 -0
  102. package/dist/components/navigation/Tabs.svelte +106 -86
  103. package/dist/components/navigation/Tabs.svelte.d.ts +8 -0
  104. package/dist/components/navigation/Topbar.svelte +94 -85
  105. package/dist/components/navigation/Topbar.svelte.d.ts +9 -0
  106. package/dist/components/patterns/ActionBar.svelte +82 -76
  107. package/dist/components/patterns/ActionBar.svelte.d.ts +10 -0
  108. package/dist/components/patterns/ChapterMark.svelte +152 -0
  109. package/dist/components/patterns/ChapterMark.svelte.d.ts +19 -0
  110. package/dist/components/patterns/ConfirmDialog.svelte +75 -64
  111. package/dist/components/patterns/ConfirmDialog.svelte.d.ts +12 -0
  112. package/dist/components/patterns/DepthPortal.svelte +123 -0
  113. package/dist/components/patterns/DepthPortal.svelte.d.ts +24 -0
  114. package/dist/components/patterns/Manifesto.svelte +171 -0
  115. package/dist/components/patterns/Manifesto.svelte.d.ts +25 -0
  116. package/dist/components/patterns/PageHeader.svelte +117 -114
  117. package/dist/components/patterns/PageHeader.svelte.d.ts +8 -0
  118. package/dist/components/patterns/PullQuote.svelte +145 -0
  119. package/dist/components/patterns/PullQuote.svelte.d.ts +23 -0
  120. package/dist/components/patterns/RegisterSwitcher.svelte +132 -0
  121. package/dist/components/patterns/RegisterSwitcher.svelte.d.ts +21 -0
  122. package/dist/components/patterns/SearchBar.svelte +59 -59
  123. package/dist/components/patterns/SearchBar.svelte.d.ts +5 -0
  124. package/dist/components/patterns/ShowcaseFrame.svelte +117 -0
  125. package/dist/components/patterns/ShowcaseFrame.svelte.d.ts +28 -0
  126. package/dist/components/patterns/TerminalBoot.svelte +118 -104
  127. package/dist/components/patterns/TerminalBoot.svelte.d.ts +12 -0
  128. package/dist/components/primitives/Divider.svelte +56 -29
  129. package/dist/components/primitives/Divider.svelte.d.ts +5 -0
  130. package/dist/components/primitives/Icon.svelte +53 -49
  131. package/dist/components/primitives/Icon.svelte.d.ts +9 -0
  132. package/dist/components/primitives/Label.svelte +45 -44
  133. package/dist/components/primitives/Label.svelte.d.ts +6 -0
  134. package/dist/components/primitives/Surface.svelte +154 -87
  135. package/dist/components/primitives/Surface.svelte.d.ts +7 -0
  136. package/dist/components/primitives/Text.svelte +130 -98
  137. package/dist/components/primitives/Text.svelte.d.ts +7 -0
  138. package/dist/components/scenes/ArchiveScene.svelte +102 -95
  139. package/dist/components/scenes/ArchiveScene.svelte.d.ts +17 -1
  140. package/dist/components/scenes/DepthScene.svelte +128 -0
  141. package/dist/components/scenes/DepthScene.svelte.d.ts +36 -0
  142. package/dist/components/scenes/LogScene.svelte +86 -77
  143. package/dist/components/scenes/LogScene.svelte.d.ts +14 -0
  144. package/dist/components/scenes/NarrativeScene.svelte +100 -92
  145. package/dist/components/scenes/NarrativeScene.svelte.d.ts +9 -0
  146. package/dist/components/scenes/ReadoutScene.svelte +131 -107
  147. package/dist/components/scenes/ReadoutScene.svelte.d.ts +14 -1
  148. package/dist/components/scenes/StageScene.svelte +111 -104
  149. package/dist/components/scenes/StageScene.svelte.d.ts +14 -0
  150. package/dist/components/system/AppShell.svelte +62 -0
  151. package/dist/components/system/AppShell.svelte.d.ts +32 -0
  152. package/dist/examples/ArcaneShard.svelte +364 -0
  153. package/dist/examples/ArcaneShard.svelte.d.ts +3 -0
  154. package/dist/examples/FieldReport.svelte +226 -223
  155. package/dist/examples/HextechForge.svelte +324 -0
  156. package/dist/examples/HextechForge.svelte.d.ts +3 -0
  157. package/dist/examples/ObservationDeck.svelte +333 -317
  158. package/dist/examples/SignalLost.svelte +191 -191
  159. package/dist/index.d.ts +15 -1
  160. package/dist/index.js +16 -1
  161. package/dist/styles.css +115 -0
  162. package/dist/system/actions/echo.js +21 -12
  163. package/dist/system/actions/resolve.js +28 -14
  164. package/dist/system/actions/reveal.js +2 -2
  165. package/dist/system/actions/surface.js +12 -2
  166. package/dist/system/depth/depth.css +49 -49
  167. package/dist/system/depth/depth.js +1 -1
  168. package/dist/system/expressions.css +80 -80
  169. package/dist/system/override-template.css +72 -72
  170. package/dist/system/register.css +74 -74
  171. package/dist/system/register.d.ts +1 -1
  172. package/dist/system/register.js +5 -1
  173. package/dist/system/scroll-lock.d.ts +6 -0
  174. package/dist/system/scroll-lock.js +23 -0
  175. package/dist/tokens/arcane.css +96 -0
  176. package/dist/tokens/hextech.css +96 -0
  177. package/dist/tokens/tokens.css +102 -86
  178. package/dist/tokens/tokens.d.ts +41 -0
  179. package/dist/tokens/tokens.js +44 -3
  180. package/dist/utils/motion.js +1 -1
  181. package/package.json +71 -60
@@ -1,86 +1,106 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
-
4
- interface TabItem {
5
- id: string;
6
- label: string;
7
- }
8
-
9
- interface Props {
10
- /** Available tabs. */
11
- tabs?: TabItem[];
12
- /** Currently active tab id. */
13
- active?: string;
14
- /** Additional CSS classes. */
15
- class?: string;
16
- /** Fires when a tab is selected with the new tab id. */
17
- onchange?: (id: string) => void;
18
- }
19
-
20
- let {
21
- tabs = [],
22
- active = '',
23
- class: className = '',
24
- onchange,
25
- }: Props = $props();
26
- </script>
27
-
28
- <div class={cn('hyvui-tabs', className)} role="tablist">
29
- {#each tabs as tab}
30
- <button
31
- type="button"
32
- role="tab"
33
- aria-selected={tab.id === active}
34
- class={cn('hyvui-tab', tab.id === active && 'hyvui-tab-active')}
35
- onclick={() => onchange?.(tab.id)}
36
- >
37
- {tab.label}
38
- </button>
39
- {/each}
40
- </div>
41
-
42
- <style>
43
- .hyvui-tabs {
44
- display: flex;
45
- flex-wrap: wrap;
46
- gap: var(--space-xs);
47
- border-bottom: 1px solid var(--line);
48
- padding-bottom: var(--space-xs);
49
- }
50
-
51
- .hyvui-tab {
52
- position: relative;
53
- font-family: var(--font-mono);
54
- font-size: 0.7rem;
55
- font-weight: 400;
56
- letter-spacing: 0.16em;
57
- text-transform: uppercase;
58
- color: var(--muted);
59
- background: transparent;
60
- border: 1px solid transparent;
61
- border-radius: var(--radius-md);
62
- padding: 0.65rem 0.85rem;
63
- cursor: pointer;
64
- transition:
65
- color var(--transition-fast),
66
- border-color var(--transition-fast),
67
- background var(--transition-fast);
68
- }
69
-
70
- .hyvui-tab:hover {
71
- color: var(--text-soft);
72
- background: linear-gradient(180deg, rgba(199, 156, 87, 0.08), transparent 76%);
73
- }
74
-
75
- .hyvui-tab-active {
76
- color: var(--accent);
77
- border-color: color-mix(in srgb, var(--accent) 34%, transparent);
78
- background: linear-gradient(180deg, rgba(199, 156, 87, 0.12), transparent 76%);
79
- }
80
-
81
- @media (prefers-reduced-motion: reduce) {
82
- .hyvui-tab {
83
- transition: none;
84
- }
85
- }
86
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+
4
+ interface TabItem {
5
+ id: string;
6
+ label: string;
7
+ }
8
+
9
+ /**
10
+ * @example
11
+ * <Tabs
12
+ * tabs={[{ id: 'data', label: 'data' }, { id: 'logs', label: 'logs' }]}
13
+ * active={activeTab}
14
+ * onchange={(id) => activeTab = id}
15
+ * />
16
+ */
17
+ interface Props {
18
+ /** Available tabs. */
19
+ tabs?: TabItem[];
20
+ /** Currently active tab id. */
21
+ active?: string;
22
+ /** Additional CSS classes. */
23
+ class?: string;
24
+ /** Fires when a tab is selected with the new tab id. */
25
+ onchange?: (id: string) => void;
26
+ }
27
+
28
+ let { tabs = [], active = '', class: className = '', onchange }: Props = $props();
29
+
30
+ let tabEls: HTMLButtonElement[] = [];
31
+
32
+ function handleKeyDown(e: KeyboardEvent, idx: number) {
33
+ let next = -1;
34
+ if (e.key === 'ArrowRight') next = (idx + 1) % tabs.length;
35
+ else if (e.key === 'ArrowLeft') next = (idx - 1 + tabs.length) % tabs.length;
36
+ else if (e.key === 'Home') next = 0;
37
+ else if (e.key === 'End') next = tabs.length - 1;
38
+ if (next === -1) return;
39
+ e.preventDefault();
40
+ onchange?.(tabs[next].id);
41
+ tabEls[next]?.focus();
42
+ }
43
+ </script>
44
+
45
+ <div class={cn('hyvui-tabs', className)} role="tablist">
46
+ {#each tabs as tab, i}
47
+ <button
48
+ bind:this={tabEls[i]}
49
+ type="button"
50
+ role="tab"
51
+ aria-selected={tab.id === active}
52
+ tabindex={tab.id === active ? 0 : -1}
53
+ class={cn('hyvui-tab', tab.id === active && 'hyvui-tab-active')}
54
+ onclick={() => onchange?.(tab.id)}
55
+ onkeydown={(e) => handleKeyDown(e, i)}
56
+ >
57
+ {tab.label}
58
+ </button>
59
+ {/each}
60
+ </div>
61
+
62
+ <style>
63
+ .hyvui-tabs {
64
+ display: flex;
65
+ flex-wrap: wrap;
66
+ gap: var(--space-xs);
67
+ border-bottom: 1px solid var(--line);
68
+ padding-bottom: var(--space-xs);
69
+ }
70
+
71
+ .hyvui-tab {
72
+ position: relative;
73
+ font-family: var(--font-mono);
74
+ font-size: 0.7rem;
75
+ font-weight: 400;
76
+ letter-spacing: 0.16em;
77
+ text-transform: uppercase;
78
+ color: var(--muted);
79
+ background: transparent;
80
+ border: 1px solid transparent;
81
+ border-radius: var(--radius-md);
82
+ padding: 0.65rem 0.85rem;
83
+ cursor: pointer;
84
+ transition:
85
+ color var(--transition-fast),
86
+ border-color var(--transition-fast),
87
+ background var(--transition-fast);
88
+ }
89
+
90
+ .hyvui-tab:hover {
91
+ color: var(--text-soft);
92
+ background: linear-gradient(180deg, rgba(199, 156, 87, 0.08), transparent 76%);
93
+ }
94
+
95
+ .hyvui-tab-active {
96
+ color: var(--accent);
97
+ border-color: color-mix(in srgb, var(--accent) 34%, transparent);
98
+ background: linear-gradient(180deg, rgba(199, 156, 87, 0.12), transparent 76%);
99
+ }
100
+
101
+ @media (prefers-reduced-motion: reduce) {
102
+ .hyvui-tab {
103
+ transition: none;
104
+ }
105
+ }
106
+ </style>
@@ -2,6 +2,14 @@ interface TabItem {
2
2
  id: string;
3
3
  label: string;
4
4
  }
5
+ /**
6
+ * @example
7
+ * <Tabs
8
+ * tabs={[{ id: 'data', label: 'data' }, { id: 'logs', label: 'logs' }]}
9
+ * active={activeTab}
10
+ * onchange={(id) => activeTab = id}
11
+ * />
12
+ */
5
13
  interface Props {
6
14
  /** Available tabs. */
7
15
  tabs?: TabItem[];
@@ -1,85 +1,94 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
- import type { Snippet } from 'svelte';
4
-
5
- interface Props {
6
- /** Additional CSS classes. */
7
- class?: string;
8
- /** Left slot content. */
9
- left?: Snippet;
10
- /** Center slot content. */
11
- center?: Snippet;
12
- /** Right slot content. */
13
- right?: Snippet;
14
- }
15
-
16
- let {
17
- class: className = '',
18
- left,
19
- center,
20
- right,
21
- }: Props = $props();
22
- </script>
23
-
24
- <header class={cn('hyvui-topbar', className)}>
25
- <div class="hyvui-topbar-left">
26
- {#if left}{@render left()}{/if}
27
- </div>
28
- <div class="hyvui-topbar-center">
29
- {#if center}{@render center()}{/if}
30
- </div>
31
- <div class="hyvui-topbar-right">
32
- {#if right}{@render right()}{/if}
33
- </div>
34
- </header>
35
-
36
- <style>
37
- .hyvui-topbar {
38
- display: grid;
39
- grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
40
- align-items: center;
41
- gap: var(--space-md);
42
- min-height: 4.5rem;
43
- padding: var(--space-sm) var(--shell-pad);
44
- background:
45
- linear-gradient(180deg, rgba(121, 166, 163, 0.06), transparent 68%),
46
- rgba(8, 9, 11, 0.86);
47
- border-bottom: 1px solid var(--line);
48
- backdrop-filter: blur(10px);
49
- }
50
-
51
- .hyvui-topbar-left {
52
- display: flex;
53
- align-items: center;
54
- gap: var(--space-sm);
55
- min-width: 0;
56
- }
57
-
58
- .hyvui-topbar-center {
59
- display: flex;
60
- align-items: center;
61
- justify-content: center;
62
- gap: var(--space-sm);
63
- min-width: 0;
64
- }
65
-
66
- .hyvui-topbar-right {
67
- display: flex;
68
- align-items: center;
69
- justify-content: flex-end;
70
- gap: var(--space-sm);
71
- min-width: 0;
72
- }
73
-
74
- @media (max-width: 720px) {
75
- .hyvui-topbar {
76
- grid-template-columns: 1fr;
77
- justify-items: stretch;
78
- }
79
-
80
- .hyvui-topbar-center,
81
- .hyvui-topbar-right {
82
- justify-content: flex-start;
83
- }
84
- }
85
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ /**
6
+ * @example
7
+ * <Topbar>
8
+ * {#snippet left()}<Text variant="caption" color="accent">hyvui</Text>{/snippet}
9
+ * {#snippet right()}
10
+ * <Button variant="ghost" size="sm">sign in</Button>
11
+ * {/snippet}
12
+ * </Topbar>
13
+ */
14
+ interface Props {
15
+ /** Additional CSS classes. */
16
+ class?: string;
17
+ /** Left slot content. */
18
+ left?: Snippet;
19
+ /** Center slot content. */
20
+ center?: Snippet;
21
+ /** Right slot content. */
22
+ right?: Snippet;
23
+ }
24
+
25
+ let { class: className = '', left, center, right }: Props = $props();
26
+ </script>
27
+
28
+ <header class={cn('hyvui-topbar', className)}>
29
+ <div class="hyvui-topbar-inner">
30
+ <div class="hyvui-topbar-left">
31
+ {#if left}{@render left()}{/if}
32
+ </div>
33
+ <div class="hyvui-topbar-center">
34
+ {#if center}{@render center()}{/if}
35
+ </div>
36
+ <div class="hyvui-topbar-right">
37
+ {#if right}{@render right()}{/if}
38
+ </div>
39
+ </div>
40
+ </header>
41
+
42
+ <style>
43
+ .hyvui-topbar {
44
+ min-height: 4.5rem;
45
+ background:
46
+ linear-gradient(180deg, rgba(121, 166, 163, 0.06), transparent 68%), rgba(8, 9, 11, 0.86);
47
+ border-bottom: 1px solid var(--line);
48
+ backdrop-filter: blur(10px);
49
+ container-type: inline-size;
50
+ }
51
+
52
+ .hyvui-topbar-inner {
53
+ display: grid;
54
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
55
+ align-items: center;
56
+ gap: var(--space-md);
57
+ padding: var(--space-sm) var(--shell-pad);
58
+ }
59
+
60
+ .hyvui-topbar-left {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: var(--space-sm);
64
+ min-width: 0;
65
+ }
66
+
67
+ .hyvui-topbar-center {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ gap: var(--space-sm);
72
+ min-width: 0;
73
+ }
74
+
75
+ .hyvui-topbar-right {
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: flex-end;
79
+ gap: var(--space-sm);
80
+ min-width: 0;
81
+ }
82
+
83
+ @container (max-width: var(--cq-sm)) {
84
+ .hyvui-topbar-inner {
85
+ grid-template-columns: 1fr;
86
+ justify-items: stretch;
87
+ }
88
+
89
+ .hyvui-topbar-center,
90
+ .hyvui-topbar-right {
91
+ justify-content: flex-start;
92
+ }
93
+ }
94
+ </style>
@@ -1,4 +1,13 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @example
4
+ * <Topbar>
5
+ * {#snippet left()}<Text variant="caption" color="accent">hyvui</Text>{/snippet}
6
+ * {#snippet right()}
7
+ * <Button variant="ghost" size="sm">sign in</Button>
8
+ * {/snippet}
9
+ * </Topbar>
10
+ */
2
11
  interface Props {
3
12
  /** Additional CSS classes. */
4
13
  class?: string;
@@ -1,76 +1,82 @@
1
- <script lang="ts">
2
- import { cn } from '../../utils/cn.js';
3
- import Button from '../inputs/Button.svelte';
4
- import Label from '../primitives/Label.svelte';
5
- import type { Snippet } from 'svelte';
6
-
7
- interface Props {
8
- /** Number of selected items. Bar is visible when count > 0. */
9
- count?: number;
10
- /** Additional CSS classes. */
11
- class?: string;
12
- /** Bulk action buttons slot. */
13
- actions?: Snippet;
14
- /** Fires when clear selection is clicked. */
15
- onclear?: () => void;
16
- }
17
-
18
- let {
19
- count = 0,
20
- class: className = '',
21
- actions,
22
- onclear,
23
- }: Props = $props();
24
- </script>
25
-
26
- {#if count > 0}
27
- <div class={cn('hyvui-action-bar', className)}>
28
- <Label color="accent">{count} selected</Label>
29
- {#if actions}
30
- <div class="hyvui-action-bar-actions">
31
- {@render actions()}
32
- </div>
33
- {/if}
34
- <Button variant="ghost" size="sm" onclick={() => onclear?.()}>clear selection</Button>
35
- </div>
36
- {/if}
37
-
38
- <style>
39
- .hyvui-action-bar {
40
- position: fixed;
41
- bottom: 1.5rem;
42
- left: 50%;
43
- transform: translateX(-50%);
44
- z-index: var(--z-overlay);
45
- display: flex;
46
- align-items: center;
47
- gap: 1rem;
48
- background: var(--surface-card);
49
- border: 1px solid rgba(255, 255, 255, 0.05);
50
- box-shadow: var(--shadow-veil);
51
- padding: 0.625rem 1.25rem;
52
- animation: actionbar-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
53
- }
54
-
55
- .hyvui-action-bar-actions {
56
- display: flex;
57
- gap: 0.5rem;
58
- }
59
-
60
- @keyframes actionbar-in {
61
- from {
62
- opacity: 0;
63
- transform: translateX(-50%) translateY(12px);
64
- }
65
- to {
66
- opacity: 1;
67
- transform: translateX(-50%) translateY(0);
68
- }
69
- }
70
-
71
- @media (prefers-reduced-motion: reduce) {
72
- .hyvui-action-bar {
73
- animation: none;
74
- }
75
- }
76
- </style>
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import Button from '../inputs/Button.svelte';
4
+ import Label from '../primitives/Label.svelte';
5
+ import type { Snippet } from 'svelte';
6
+
7
+ /**
8
+ * @remarks Use on any multi-select list or table. Fixed, bottom-center. Renders nothing when count is 0.
9
+ * @example
10
+ * <ActionBar count={selected.length} onclear={() => selected = []}>
11
+ * {#snippet actions()}
12
+ * <Button variant="ghost" size="sm" onclick={exportSelected}>export</Button>
13
+ * <Button variant="destructive" size="sm" onclick={deleteSelected}>delete</Button>
14
+ * {/snippet}
15
+ * </ActionBar>
16
+ */
17
+ interface Props {
18
+ /** Number of selected items. Bar is visible when count > 0. */
19
+ count?: number;
20
+ /** Additional CSS classes. */
21
+ class?: string;
22
+ /** Bulk action buttons slot. */
23
+ actions?: Snippet;
24
+ /** Fires when clear selection is clicked. */
25
+ onclear?: () => void;
26
+ }
27
+
28
+ let { count = 0, class: className = '', actions, onclear }: Props = $props();
29
+ </script>
30
+
31
+ {#if count > 0}
32
+ <div class={cn('hyvui-action-bar', className)}>
33
+ <Label color="accent">{count} selected</Label>
34
+ {#if actions}
35
+ <div class="hyvui-action-bar-actions">
36
+ {@render actions()}
37
+ </div>
38
+ {/if}
39
+ <Button variant="ghost" size="sm" onclick={() => onclear?.()}>clear selection</Button>
40
+ </div>
41
+ {/if}
42
+
43
+ <style>
44
+ .hyvui-action-bar {
45
+ position: fixed;
46
+ bottom: 1.5rem;
47
+ left: 50%;
48
+ transform: translateX(-50%);
49
+ z-index: var(--z-overlay);
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 1rem;
53
+ background: var(--surface-card);
54
+ border: 1px solid rgba(255, 255, 255, 0.05);
55
+ box-shadow: var(--shadow-veil);
56
+ padding: 0.625rem 1.25rem;
57
+ backface-visibility: hidden;
58
+ animation: actionbar-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
59
+ }
60
+
61
+ .hyvui-action-bar-actions {
62
+ display: flex;
63
+ gap: 0.5rem;
64
+ }
65
+
66
+ @keyframes actionbar-in {
67
+ from {
68
+ opacity: 0;
69
+ transform: translateX(-50%) translateY(12px);
70
+ }
71
+ to {
72
+ opacity: 1;
73
+ transform: translateX(-50%) translateY(0);
74
+ }
75
+ }
76
+
77
+ @media (prefers-reduced-motion: reduce) {
78
+ .hyvui-action-bar {
79
+ animation: none;
80
+ }
81
+ }
82
+ </style>
@@ -1,4 +1,14 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * @remarks Use on any multi-select list or table. Fixed, bottom-center. Renders nothing when count is 0.
4
+ * @example
5
+ * <ActionBar count={selected.length} onclear={() => selected = []}>
6
+ * {#snippet actions()}
7
+ * <Button variant="ghost" size="sm" onclick={exportSelected}>export</Button>
8
+ * <Button variant="destructive" size="sm" onclick={deleteSelected}>delete</Button>
9
+ * {/snippet}
10
+ * </ActionBar>
11
+ */
2
12
  interface Props {
3
13
  /** Number of selected items. Bar is visible when count > 0. */
4
14
  count?: number;