@a4ui/core 0.1.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/dist/index.d.ts +53 -0
  4. package/dist/index.js +2157 -0
  5. package/dist/layout/AppShell.d.ts +18 -0
  6. package/dist/layout/EffectsToggle.d.ts +1 -0
  7. package/dist/layout/NavGroup.d.ts +6 -0
  8. package/dist/layout/SpaceBackground.d.ts +1 -0
  9. package/dist/layout/ThemeToggle.d.ts +2 -0
  10. package/dist/lib/cn.d.ts +3 -0
  11. package/dist/lib/effects.d.ts +4 -0
  12. package/dist/lib/media.d.ts +1 -0
  13. package/dist/lib/motion.d.ts +24 -0
  14. package/dist/lib/theme.d.ts +10 -0
  15. package/dist/lib/virtual.d.ts +2 -0
  16. package/dist/styles.css +305 -0
  17. package/dist/ui/Accordion.d.ts +13 -0
  18. package/dist/ui/Alert.d.ts +9 -0
  19. package/dist/ui/AlertDialog.d.ts +9 -0
  20. package/dist/ui/Avatar.d.ts +9 -0
  21. package/dist/ui/Badge.d.ts +8 -0
  22. package/dist/ui/Breadcrumb.d.ts +11 -0
  23. package/dist/ui/Button.d.ts +10 -0
  24. package/dist/ui/Card.d.ts +18 -0
  25. package/dist/ui/Checkbox.d.ts +9 -0
  26. package/dist/ui/Combobox.d.ts +10 -0
  27. package/dist/ui/ContextMenu.d.ts +13 -0
  28. package/dist/ui/DateField.d.ts +10 -0
  29. package/dist/ui/Drawer.d.ts +10 -0
  30. package/dist/ui/Dropdown.d.ts +17 -0
  31. package/dist/ui/Dropzone.d.ts +13 -0
  32. package/dist/ui/HoverCard.d.ts +7 -0
  33. package/dist/ui/Input.d.ts +8 -0
  34. package/dist/ui/Meter.d.ts +9 -0
  35. package/dist/ui/Modal.d.ts +10 -0
  36. package/dist/ui/NumberInput.d.ts +10 -0
  37. package/dist/ui/PageHeader.d.ts +9 -0
  38. package/dist/ui/Pagination.d.ts +9 -0
  39. package/dist/ui/Popover.d.ts +7 -0
  40. package/dist/ui/Progress.d.ts +9 -0
  41. package/dist/ui/RadioGroup.d.ts +15 -0
  42. package/dist/ui/SegmentedControl.d.ts +13 -0
  43. package/dist/ui/Select.d.ts +8 -0
  44. package/dist/ui/Separator.d.ts +7 -0
  45. package/dist/ui/Skeleton.d.ts +6 -0
  46. package/dist/ui/Slider.d.ts +12 -0
  47. package/dist/ui/Spinner.d.ts +7 -0
  48. package/dist/ui/Stat.d.ts +16 -0
  49. package/dist/ui/Switch.d.ts +10 -0
  50. package/dist/ui/Table.d.ts +11 -0
  51. package/dist/ui/Tabs.d.ts +14 -0
  52. package/dist/ui/Textarea.d.ts +8 -0
  53. package/dist/ui/Toast.d.ts +9 -0
  54. package/dist/ui/Toggle.d.ts +8 -0
  55. package/dist/ui/ToggleGroup.d.ts +13 -0
  56. package/dist/ui/Tooltip.d.ts +7 -0
  57. package/dist/ui/VirtualList.d.ts +15 -0
  58. package/package.json +82 -0
  59. package/preset.js +166 -0
@@ -0,0 +1,18 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface AppShellProps extends ParentProps {
3
+ /** Left column (e.g. a Sidebar). Rendered as a flex child; owns its own width. */
4
+ sidebar?: JSX.Element;
5
+ /** Top bar inside the content column, above <main>. */
6
+ topbar?: JSX.Element;
7
+ /** Full-width strip above the topbar (e.g. a demo/announcement banner). */
8
+ banner?: JSX.Element;
9
+ /** Fixed z-0 backdrop. Defaults to <SpaceBackground/>; pass a node to override,
10
+ or `null` for a plain background. */
11
+ background?: JSX.Element;
12
+ /** Max content width for <main>. Default '1400px'. */
13
+ maxWidth?: string;
14
+ /** Override the default error fallback shown when a route throws. */
15
+ errorFallback?: (err: unknown, reset: () => void) => JSX.Element;
16
+ }
17
+ export declare function AppShell(props: ParentProps<AppShellProps>): JSX.Element;
18
+ export {};
@@ -0,0 +1 @@
1
+ export declare function EffectsToggle(): import("solid-js").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface NavGroupProps extends ParentProps {
3
+ title: string;
4
+ }
5
+ export declare function NavGroup(props: NavGroupProps): JSX.Element;
6
+ export {};
@@ -0,0 +1 @@
1
+ export declare function SpaceBackground(): import("solid-js").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { JSX } from 'solid-js';
2
+ export declare function ThemeToggle(): JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { ClassValue } from 'clsx';
2
+ /** Merge Tailwind class lists, resolving conflicting utilities left-to-right. */
3
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,4 @@
1
+ export declare function useEffects(): import('solid-js').Accessor<boolean>;
2
+ /** True when visual effects are OFF (calm mode). Read by motion + charts. */
3
+ export declare function isCalm(): boolean;
4
+ export declare function setEffects(on: boolean): void;
@@ -0,0 +1 @@
1
+ export declare function useMediaQuery(query: string): () => boolean;
@@ -0,0 +1,24 @@
1
+ import { Accessor } from 'solid-js';
2
+ /**
3
+ * Snapshot of the user's reduced-motion preference at call time. Not
4
+ * reactive to preference changes mid-session (matches theme.ts's one-shot
5
+ * environment read) — reload picks up changes.
6
+ */
7
+ export declare function prefersReducedMotion(): boolean;
8
+ export declare function useMotionForced(): Accessor<boolean>;
9
+ export declare function setMotionForced(on: boolean): void;
10
+ /**
11
+ * Effective reduced-motion: reduced when calm mode (visual effects OFF) is on,
12
+ * or when the OS asks for reduced motion and the user hasn't forced it. JS-driven
13
+ * motion (SpaceBackground, count-up) gates on this rather than
14
+ * prefersReducedMotion() directly.
15
+ */
16
+ export declare function motionReduced(): boolean;
17
+ /**
18
+ * Tweens a numeric signal toward `target()` using requestAnimationFrame +
19
+ * an ease-out curve (solid-motionone/@motionone don't expose spring easing
20
+ * yet, and this needs to interpolate a plain number rather than a DOM
21
+ * property, so it's a small hand-rolled WAAPI-adjacent tween for KPI count-up).
22
+ * Jumps straight to the target under prefers-reduced-motion.
23
+ */
24
+ export declare function createCountUp(target: Accessor<number>, durationMs?: number): Accessor<number>;
@@ -0,0 +1,10 @@
1
+ export type Theme = 'dark' | 'light';
2
+ /** The persisted choice, defaulting to dark when nothing is stored. */
3
+ export declare function storedTheme(): Theme;
4
+ /** Reflect the theme onto <html data-theme>: dark is the default (no attribute). */
5
+ export declare function applyTheme(theme: Theme): void;
6
+ /** Persist and apply a theme choice. */
7
+ export declare function setTheme(theme: Theme): void;
8
+ export declare function toggled(theme: Theme): Theme;
9
+ export declare function useTheme(): import('solid-js').Accessor<Theme>;
10
+ export declare function toggleTheme(): void;
@@ -0,0 +1,2 @@
1
+ import { Accessor } from 'solid-js';
2
+ export declare function remeasureAfterLayout(scrollEl: Accessor<HTMLElement | undefined>, setScrollEl: (v: HTMLElement | undefined) => void): void;
@@ -0,0 +1,305 @@
1
+ /* A4ui — Spatial Glass design tokens + motion.
2
+ *
3
+ * Pure CSS (no @tailwind / @apply) so it can be imported directly by any
4
+ * consumer: `import 'a4ui/styles.css'`. Dark "night" theme is the default;
5
+ * `data-theme="light"` on the root opts into the light palette.
6
+ *
7
+ * Extracted verbatim from the source project
8
+ * (sonora precision/alfredorust/solid/src/index.css) — keep in sync until that
9
+ * app consumes this package instead. */
10
+
11
+ :root {
12
+ --background: 222 47% 7%;
13
+ --foreground: 213 31% 91%;
14
+ --card: 222 40% 11%;
15
+ --card-foreground: 213 31% 91%;
16
+ --muted: 217 33% 17%;
17
+ /* 75% (not 65%) for WCAG AA contrast on glass/dark surfaces (pa11y/axe). */
18
+ --muted-foreground: 215 25% 75%;
19
+ --border: 217 30% 22%;
20
+ --input: 217 30% 22%;
21
+ --primary: 217 91% 60%;
22
+ --primary-foreground: 0 0% 100%;
23
+ --accent: 199 89% 55%;
24
+ --accent-foreground: 0 0% 100%;
25
+ --ring: 217 91% 60%;
26
+ --destructive: 0 72% 55%;
27
+ --destructive-foreground: 0 0% 100%;
28
+
29
+ /* Semantic data colors (financial direction) — constant across themes. */
30
+ --data-emit: 160 84% 39%;
31
+ --data-received: 347 89% 61%;
32
+ --data-net: 199 89% 48%;
33
+
34
+ --font-sans: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
35
+ --font-mono: 'IBM Plex Mono', ui-monospace, monospace;
36
+ --sidebar-w: 248px;
37
+ --sidebar-w-collapsed: 68px;
38
+
39
+ /* Shadow color for glass surfaces (consumed by the glass plugin in preset.js).
40
+ Undefined in the source project, so its .card box-shadow silently dropped —
41
+ defined here so the intended elevation renders. Low alpha in use, so one
42
+ dark value covers both themes. */
43
+ --shadow: 222 47% 4%;
44
+ --radius-xl: 1rem;
45
+ }
46
+
47
+ :root[data-theme='light'] {
48
+ --background: 214 32% 95%;
49
+ --foreground: 222 47% 11%;
50
+ --card: 0 0% 100%;
51
+ --card-foreground: 222 47% 11%;
52
+ --muted: 214 30% 92%;
53
+ /* 38% (not 47%) for WCAG AA contrast on light/glass surfaces (pa11y/axe). */
54
+ --muted-foreground: 215 22% 38%;
55
+ --border: 214 24% 84%;
56
+ --input: 214 32% 91%;
57
+ --primary: 217 91% 55%;
58
+ --primary-foreground: 0 0% 100%;
59
+ --accent: 199 89% 48%;
60
+ --accent-foreground: 0 0% 100%;
61
+ --ring: 217 91% 55%;
62
+ --destructive: 0 72% 51%;
63
+ --destructive-foreground: 0 0% 100%;
64
+ }
65
+
66
+ body {
67
+ background: hsl(var(--background));
68
+ color: hsl(var(--foreground));
69
+ font-family: var(--font-sans);
70
+ -webkit-font-smoothing: antialiased;
71
+ font-feature-settings: 'cv02', 'cv03', 'cv04';
72
+ }
73
+
74
+ /* ---- Motion (transform/opacity only, short & functional) --------------- */
75
+
76
+ /* Route/page cross-fade (AppShell wraps routed content in a <Transition>). */
77
+ .page-enter-active,
78
+ .page-exit-active { transition: opacity 0.16s ease-out; }
79
+ .page-enter,
80
+ .page-exit-to { opacity: 0; }
81
+
82
+ /* Modal — MUST be @keyframes (Kobalte Dialog presence listens for
83
+ animationend, not transitionend, or the exit never resolves). */
84
+ @keyframes modal-overlay-in { from { opacity: 0; } to { opacity: 1; } }
85
+ @keyframes modal-overlay-out { from { opacity: 1; } to { opacity: 0; } }
86
+ @keyframes modal-content-in {
87
+ from { opacity: 0; transform: scale(0.96) translateY(4px); }
88
+ to { opacity: 1; transform: scale(1) translateY(0); }
89
+ }
90
+ @keyframes modal-content-out {
91
+ from { opacity: 1; transform: scale(1) translateY(0); }
92
+ to { opacity: 0; transform: scale(0.96) translateY(4px); }
93
+ }
94
+ .modal-overlay[data-expanded] { animation: modal-overlay-in 0.15s ease-out; }
95
+ .modal-overlay[data-closed] { animation: modal-overlay-out 0.15s ease-in; }
96
+ .modal-content[data-expanded] { animation: modal-content-in 0.18s ease-out; }
97
+ .modal-content[data-closed] { animation: modal-content-out 0.15s ease-in; }
98
+
99
+ /* Toast — same animationend-only presence mechanism as Dialog. */
100
+ @keyframes toast-in {
101
+ from { opacity: 0; transform: translateX(16px); }
102
+ to { opacity: 1; transform: translateX(0); }
103
+ }
104
+ @keyframes toast-out {
105
+ from { opacity: 1; transform: translateX(0); }
106
+ to { opacity: 0; transform: translateX(16px); }
107
+ }
108
+ .toast-item[data-opened] { animation: toast-in 0.2s ease-out; }
109
+ .toast-item[data-closed] { animation: toast-out 0.18s ease-in; }
110
+
111
+ /* Table row enter/exit fade. */
112
+ .row-enter-active,
113
+ .row-exit-active { transition: opacity 0.15s ease-out; }
114
+ .row-enter,
115
+ .row-exit-to { opacity: 0; }
116
+
117
+ /* Drawer / Modal drawer-variant slide-over (Kobalte Dialog presence →
118
+ animationend keyframes, keyed off data-expanded/data-closed like Modal). */
119
+ @keyframes drawer-in {
120
+ from { transform: translateX(100%); }
121
+ to { transform: translateX(0); }
122
+ }
123
+ @keyframes drawer-out {
124
+ from { transform: translateX(0); }
125
+ to { transform: translateX(100%); }
126
+ }
127
+ .drawer-content[data-expanded] { animation: drawer-in 0.28s cubic-bezier(0.16, 1, 0.3, 1); }
128
+ .drawer-content[data-closed] { animation: drawer-out 0.2s ease-in; }
129
+
130
+ /* Reduced motion: resolve near-instantly rather than removing outright, so
131
+ libraries that gate DOM unmount on transitionend/animationend (Kobalte
132
+ Dialog/Toast, solid-transition-group) still fire the event. Add
133
+ `force-motion` to <html> to opt back in (the ⚡ / effects toggle). */
134
+ @media (prefers-reduced-motion: reduce) {
135
+ html:not(.force-motion) *,
136
+ html:not(.force-motion) *::before,
137
+ html:not(.force-motion) *::after {
138
+ animation-duration: 0.001ms !important;
139
+ animation-iteration-count: 1 !important;
140
+ transition-duration: 0.001ms !important;
141
+ scroll-behavior: auto !important;
142
+ }
143
+ }
144
+
145
+ /* A4ui — starfield backdrop styles for <SpaceBackground/>.
146
+ *
147
+ * Extracted from the source project's space-theme.css. Mount SpaceBackground as
148
+ * a single fixed full-viewport layer BEHIND all content (z-index 0), with app
149
+ * content at z-index >= 10 (AppShell already does this). Bundled into
150
+ * `a4ui/styles.css` after the component surfaces. */
151
+
152
+ #space { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
153
+
154
+ #space .sky {
155
+ position: absolute; inset: 0;
156
+ background:
157
+ radial-gradient(1200px 700px at 82% -8%, hsl(217 91% 60% / .34), transparent 60%),
158
+ radial-gradient(900px 600px at 8% 12%, hsl(275 80% 55% / .28), transparent 60%),
159
+ radial-gradient(1000px 800px at 50% 120%, hsl(199 89% 55% / .24), transparent 55%),
160
+ radial-gradient(700px 500px at 30% 55%, hsl(330 80% 55% / .14), transparent 60%),
161
+ hsl(var(--background));
162
+ }
163
+ [data-theme='light'] #space .sky {
164
+ background:
165
+ radial-gradient(1100px 680px at 84% -10%, hsl(38 95% 70% / .38), transparent 60%),
166
+ radial-gradient(900px 600px at 6% 8%, hsl(217 91% 70% / .32), transparent 60%),
167
+ radial-gradient(1000px 820px at 50% 120%, hsl(275 70% 75% / .26), transparent 55%),
168
+ radial-gradient(700px 500px at 30% 55%, hsl(340 85% 70% / .18), transparent 60%),
169
+ hsl(var(--background));
170
+ }
171
+ @keyframes nebulaShift { 0%, 100% { filter: hue-rotate(0deg); } 50% { filter: hue-rotate(18deg); } }
172
+
173
+ /* Aurora — dark theme only */
174
+ #space .aurora {
175
+ position: absolute; top: -10%; left: -10%; right: -10%; height: 46%;
176
+ background: linear-gradient(180deg, hsl(160 84% 45% / .16), hsl(199 89% 55% / .10) 45%, transparent 80%);
177
+ filter: blur(40px); opacity: .55; mix-blend-mode: screen;
178
+ }
179
+ [data-theme='light'] #space .aurora { display: none; }
180
+ @keyframes auroraSway { 0%,100% { transform: translateX(-2%) scaleY(1); opacity: .5; } 50% { transform: translateX(3%) scaleY(1.08); opacity: .68; } }
181
+
182
+ /* Randomized starfield — each star is generated in SpaceBackground.tsx with a
183
+ random position/size/brightness/bloom, so there's no visible tiling pattern.
184
+ Static (no drift): moving the field behind the frosted cards re-blurs every
185
+ frame and felt laggy; a subset twinkles for life instead. */
186
+ #space #starfield { position: absolute; inset: 0; }
187
+ [data-theme='light'] #space #starfield { opacity: 0.85; }
188
+ /* A few stars drift smoothly like the satellite: each is a tiny element moving
189
+ via its own transform (GPU-composited, cheap), NOT the whole field. Uses
190
+ `alternate` so it eases out and back with no loop jump. Per-star --dx/--dy. */
191
+ @keyframes starDrift { from { transform: translate(0, 0); } to { transform: translate(var(--dx, 0), var(--dy, 0)); } }
192
+
193
+ /* Rocket exhaust flame (custom SVG rocket in SpaceBackground.tsx) — flickers. */
194
+ .rk-flame { transform-box: fill-box; transform-origin: 50% 0%; animation: rocketFlame 0.12s ease-in-out infinite alternate; }
195
+ @keyframes rocketFlame { from { transform: scaleY(0.8); opacity: 0.85; } to { transform: scaleY(1.06); opacity: 1; } }
196
+
197
+ /* Legacy tiled star layers (kept for parity; the current SpaceBackground scatters
198
+ individual stars into #starfield instead). Sized generously: small dots nearly
199
+ vanish under backdrop-filter blur, so keep them >= 2.5px. */
200
+ #space .stars {
201
+ position: absolute; inset: -50%; background-repeat: repeat;
202
+ background-image:
203
+ radial-gradient(4px 4px at 20px 30px, hsl(var(--foreground)), transparent),
204
+ radial-gradient(3.6px 3.6px at 120px 90px, hsl(var(--foreground)), transparent),
205
+ radial-gradient(3.2px 3.2px at 210px 160px, hsl(217 91% 78%), transparent),
206
+ radial-gradient(4.8px 4.8px at 300px 60px, hsl(199 89% 82%), transparent),
207
+ radial-gradient(3.4px 3.4px at 380px 220px, hsl(330 80% 84%), transparent),
208
+ radial-gradient(3px 3px at 90px 190px, hsl(var(--foreground)), transparent),
209
+ radial-gradient(2.8px 2.8px at 260px 250px, hsl(48 90% 82%), transparent);
210
+ background-size: 420px 300px; opacity: 1; animation: drift 140s linear infinite;
211
+ }
212
+ [data-theme='light'] #space .stars {
213
+ background-image:
214
+ radial-gradient(4px 4px at 20px 30px, hsl(38 92% 50%), transparent),
215
+ radial-gradient(3.6px 3.6px at 120px 90px, hsl(42 90% 52%), transparent),
216
+ radial-gradient(3.2px 3.2px at 210px 160px, hsl(32 88% 48%), transparent),
217
+ radial-gradient(4.8px 4.8px at 300px 60px, hsl(45 95% 55%), transparent),
218
+ radial-gradient(3.4px 3.4px at 380px 220px, hsl(28 85% 50%), transparent),
219
+ radial-gradient(3px 3px at 90px 190px, hsl(40 90% 50%), transparent),
220
+ radial-gradient(2.8px 2.8px at 260px 250px, hsl(48 90% 52%), transparent);
221
+ }
222
+ #space .stars.s2 { background-size: 640px 480px; opacity: .85; animation-duration: 200s; }
223
+ #space .stars.s3 {
224
+ background-size: 260px 190px; opacity: 1; animation-duration: 95s;
225
+ background-image:
226
+ radial-gradient(6px 6px at 40px 50px, hsl(var(--foreground)), transparent),
227
+ radial-gradient(5.6px 5.6px at 160px 130px, hsl(199 89% 85%), transparent),
228
+ radial-gradient(5.8px 5.8px at 250px 40px, hsl(275 80% 86%), transparent),
229
+ radial-gradient(5px 5px at 90px 20px, hsl(330 85% 85%), transparent);
230
+ }
231
+ [data-theme='light'] #space .stars.s3 {
232
+ opacity: .8;
233
+ background-image:
234
+ radial-gradient(6px 6px at 40px 50px, hsl(38 92% 50%), transparent),
235
+ radial-gradient(5.6px 5.6px at 160px 130px, hsl(45 95% 54%), transparent),
236
+ radial-gradient(5.8px 5.8px at 250px 40px, hsl(30 88% 48%), transparent),
237
+ radial-gradient(5px 5px at 90px 20px, hsl(50 92% 55%), transparent);
238
+ }
239
+ @keyframes drift { from { transform: translate3d(0,0,0); } to { transform: translate3d(-420px,-300px,0); } }
240
+
241
+ /* Individually-placed twinkling stars */
242
+ .twinkle {
243
+ position: absolute; width: 5px; height: 5px; border-radius: 50%;
244
+ background: hsl(var(--foreground)); box-shadow: 0 0 14px 3px hsl(var(--foreground) / .9);
245
+ animation: twinkle 3.2s ease-in-out infinite;
246
+ }
247
+ [data-theme='light'] .twinkle { background: hsl(40 92% 50%); box-shadow: 0 0 14px 3px hsl(40 92% 50% / .85); }
248
+ @keyframes twinkle { 0%,100% { opacity: .25; transform: scale(.6); } 50% { opacity: 1; transform: scale(1.15); } }
249
+
250
+ /* Constellations — thin line art connecting a handful of stars */
251
+ #space .constellation { position: absolute; opacity: 1; }
252
+ [data-theme='light'] #space .constellation { opacity: .6; }
253
+ [data-theme='light'] #space .constellation .cline { stroke: hsl(38 92% 50%) !important; }
254
+ [data-theme='light'] #space .constellation .cdot { fill: hsl(222 47% 20%) !important; }
255
+
256
+ /* Planets / moons — decorative, corner-anchored, gentle float */
257
+ .planet { border-radius: 50%; }
258
+ .planet::after {
259
+ content: ''; position: absolute; inset: -34% -55%; border-radius: 50%;
260
+ border: 3px solid hsl(var(--foreground) / .18); transform: rotate(-24deg);
261
+ }
262
+ .planet-glow { border-radius: 50%; filter: blur(2px); }
263
+ @keyframes floaty { 0%,100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-14px) rotate(4deg); } }
264
+ .floaty { animation: floaty 12s ease-in-out infinite; }
265
+ .floaty.slow { animation-duration: 18s; }
266
+
267
+ /* Asteroid belt (small drifting rocks) */
268
+ .asteroid { border-radius: 40% 55% 50% 45%; background: hsl(var(--foreground) / .35); }
269
+ @keyframes asteroidDrift { 0%,100% { transform: translate(0,0) rotate(0deg); } 50% { transform: translate(-8px,6px) rotate(25deg); } }
270
+
271
+ /* Shooting star — bright core + tapered glowing trail */
272
+ .shooter {
273
+ position: absolute; height: 2.5px; border-radius: 999px; transform-origin: left center;
274
+ background: linear-gradient(90deg, hsla(0,0%,100%,0) 0%, hsla(199,90%,85%,.55) 55%, hsla(0,0%,100%,.98) 100%);
275
+ filter: blur(.2px) drop-shadow(0 0 3px hsla(199,90%,80%,.5));
276
+ }
277
+ .shooter::before {
278
+ content: ''; position: absolute; right: -2px; top: 50%; width: 6px; height: 6px; border-radius: 50%;
279
+ transform: translateY(-50%); background: radial-gradient(circle, #fff 0%, hsla(199,95%,88%,.95) 50%, transparent 75%);
280
+ box-shadow: 0 0 8px 2px #fff, 0 0 20px 7px hsla(199,90%,75%,.85), 0 0 38px 14px hsla(199,90%,60%,.4);
281
+ }
282
+ .shooter::after {
283
+ content: ''; position: absolute; left: 0; top: 50%; width: 55%; height: 1px; transform: translateY(-50%);
284
+ background: hsla(199,85%,92%,.65); filter: blur(2px);
285
+ }
286
+
287
+ /* Satellite (drifting glyph, e.g. a lucide "satellite" icon) */
288
+ @keyframes satelliteDrift { from { transform: translate(0,0) rotate(-18deg); } to { transform: translate(126vw, 34vh) rotate(-18deg); } }
289
+ #satellite { animation: satelliteDrift 46s linear infinite; }
290
+
291
+ /* Cursor-following ambient glow (nebula that trails the pointer) */
292
+ #cursorGlow {
293
+ border-radius: 50%; transform: translate(-50%,-50%);
294
+ background: radial-gradient(circle, hsl(217 91% 60% / .10), transparent 70%);
295
+ opacity: 0; transition: opacity .4s ease;
296
+ }
297
+
298
+ @media (prefers-reduced-motion: reduce) {
299
+ html:not(.force-motion) #space .stars, html:not(.force-motion) .twinkle,
300
+ html:not(.force-motion) .floaty, html:not(.force-motion) .shooter,
301
+ html:not(.force-motion) #satellite, html:not(.force-motion) .asteroid { animation: none !important; }
302
+ html:not(.force-motion) #cursorGlow { display: none !important; }
303
+ html:not(.force-motion) #space .sky, html:not(.force-motion) #space .aurora { animation: none !important; }
304
+ .card.glow-edge::before { display: none; }
305
+ }
@@ -0,0 +1,13 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface AccordionItem {
3
+ value: string;
4
+ title: string;
5
+ content: JSX.Element;
6
+ }
7
+ interface AccordionProps {
8
+ items: AccordionItem[];
9
+ multiple?: boolean;
10
+ class?: string;
11
+ }
12
+ export declare function Accordion(props: AccordionProps): JSX.Element;
13
+ export {};
@@ -0,0 +1,9 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ export type AlertTone = 'info' | 'success' | 'warning' | 'danger';
3
+ interface AlertProps extends ParentProps {
4
+ tone?: AlertTone;
5
+ title?: string;
6
+ class?: string;
7
+ }
8
+ export declare function Alert(props: AlertProps): JSX.Element;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface AlertDialogProps extends ParentProps {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ title?: string;
6
+ class?: string;
7
+ }
8
+ export declare function AlertDialog(props: AlertDialogProps): JSX.Element;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { JSX } from 'solid-js';
2
+ interface AvatarProps {
3
+ src?: string;
4
+ alt?: string;
5
+ fallback: string;
6
+ class?: string;
7
+ }
8
+ export declare function Avatar(props: AvatarProps): JSX.Element;
9
+ export {};
@@ -0,0 +1,8 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ export type BadgeTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
3
+ interface BadgeProps extends ParentProps {
4
+ tone?: BadgeTone;
5
+ class?: string;
6
+ }
7
+ export declare function Badge(props: BadgeProps): JSX.Element;
8
+ export {};
@@ -0,0 +1,11 @@
1
+ import { JSX } from 'solid-js';
2
+ export interface BreadcrumbItem {
3
+ label: string;
4
+ href?: string;
5
+ }
6
+ interface BreadcrumbProps {
7
+ items: BreadcrumbItem[];
8
+ class?: string;
9
+ }
10
+ export declare function Breadcrumb(props: BreadcrumbProps): JSX.Element;
11
+ export {};
@@ -0,0 +1,10 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost';
3
+ interface ButtonProps extends ParentProps, Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
4
+ variant?: ButtonVariant;
5
+ class?: string;
6
+ /** Defaults to "button" so action buttons inside a form never submit it by accident. */
7
+ type?: 'button' | 'submit' | 'reset';
8
+ }
9
+ export declare function Button(props: ButtonProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,18 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface DivProps extends ParentProps {
3
+ class?: string;
4
+ }
5
+ interface CardProps extends DivProps {
6
+ /** Frosted "space glass" surface (`.card`) instead of the opaque default. */
7
+ glass?: boolean;
8
+ /**
9
+ * Cursor-following edge glow (only meaningful with `glass`). Defaults to ON
10
+ * for glass cards so the look is uniform; pass `glow={false}` to opt out.
11
+ */
12
+ glow?: boolean;
13
+ }
14
+ export declare function Card(props: CardProps): JSX.Element;
15
+ export declare function CardHeader(props: DivProps): JSX.Element;
16
+ export declare function CardTitle(props: DivProps): JSX.Element;
17
+ export declare function CardContent(props: DivProps): JSX.Element;
18
+ export {};
@@ -0,0 +1,9 @@
1
+ import { JSX } from 'solid-js';
2
+ interface CheckboxProps {
3
+ checked: boolean;
4
+ onChange: (checked: boolean) => void;
5
+ label: string;
6
+ class?: string;
7
+ }
8
+ export declare function Checkbox(props: CheckboxProps): JSX.Element;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import { JSX } from 'solid-js';
2
+ interface ComboboxProps {
3
+ options: string[];
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ placeholder?: string;
7
+ class?: string;
8
+ }
9
+ export declare function Combobox(props: ComboboxProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,13 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ export interface ContextMenuItem {
3
+ label: string;
4
+ onSelect: () => void;
5
+ destructive?: boolean;
6
+ disabled?: boolean;
7
+ }
8
+ interface ContextMenuProps extends ParentProps {
9
+ items: ContextMenuItem[];
10
+ class?: string;
11
+ }
12
+ export declare function ContextMenu(props: ContextMenuProps): JSX.Element;
13
+ export {};
@@ -0,0 +1,10 @@
1
+ import { JSX } from 'solid-js';
2
+ interface DateFieldProps {
3
+ value: string;
4
+ onChange: (value: string) => void;
5
+ label?: string;
6
+ disabled?: boolean;
7
+ class?: string;
8
+ }
9
+ export declare function DateField(props: DateFieldProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,10 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface DrawerProps extends ParentProps {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ title?: string;
6
+ subtitle?: string;
7
+ class?: string;
8
+ }
9
+ export declare function Drawer(props: DrawerProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,17 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ export interface DropdownItem {
3
+ label: string;
4
+ onSelect: () => void;
5
+ destructive?: boolean;
6
+ disabled?: boolean;
7
+ }
8
+ interface DropdownProps extends ParentProps {
9
+ items: DropdownItem[];
10
+ class?: string;
11
+ /** Accessible name for the trigger. Pass this instead of nesting a `<button>`
12
+ inside — the Trigger IS the button, so its children must be non-interactive. */
13
+ label?: string;
14
+ }
15
+ /** `props.children` is the trigger's (non-interactive) content. */
16
+ export declare function Dropdown(props: DropdownProps): JSX.Element;
17
+ export {};
@@ -0,0 +1,13 @@
1
+ import { JSX } from 'solid-js';
2
+ interface DropzoneProps {
3
+ onFiles: (files: File[]) => void;
4
+ /** `accept` attribute for the hidden input, e.g. ".xml,.zip". */
5
+ accept?: string;
6
+ multiple?: boolean;
7
+ disabled?: boolean;
8
+ /** Optional hint line under the primary label. */
9
+ hint?: string;
10
+ label?: string;
11
+ }
12
+ export declare function Dropzone(props: DropzoneProps): JSX.Element;
13
+ export {};
@@ -0,0 +1,7 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface HoverCardProps extends ParentProps {
3
+ trigger: JSX.Element;
4
+ class?: string;
5
+ }
6
+ export declare function HoverCard(props: HoverCardProps): JSX.Element;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ import { JSX } from 'solid-js';
2
+ interface InputProps extends Omit<JSX.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onInput'> {
3
+ value: string;
4
+ onInput: (value: string) => void;
5
+ class?: string;
6
+ }
7
+ export declare function Input(props: InputProps): JSX.Element;
8
+ export {};
@@ -0,0 +1,9 @@
1
+ import { JSX } from 'solid-js';
2
+ interface MeterProps {
3
+ value: number;
4
+ max?: number;
5
+ label?: string;
6
+ class?: string;
7
+ }
8
+ export declare function Meter(props: MeterProps): JSX.Element;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import { JSX, ParentProps } from 'solid-js';
2
+ interface ModalProps extends ParentProps {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ title?: string;
6
+ variant?: 'drawer' | 'center';
7
+ class?: string;
8
+ }
9
+ export declare function Modal(props: ModalProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,10 @@
1
+ import { JSX } from 'solid-js';
2
+ interface NumberInputProps {
3
+ value: number;
4
+ onChange: (value: number) => void;
5
+ min?: number;
6
+ max?: number;
7
+ class?: string;
8
+ }
9
+ export declare function NumberInput(props: NumberInputProps): JSX.Element;
10
+ export {};
@@ -0,0 +1,9 @@
1
+ import { JSX } from 'solid-js';
2
+ interface PageHeaderProps {
3
+ title: string;
4
+ subtitle?: string;
5
+ breadcrumb?: string[];
6
+ actions?: JSX.Element;
7
+ }
8
+ export declare function PageHeader(props: PageHeaderProps): JSX.Element;
9
+ export {};