@joewinke/jatui 0.1.31 → 0.2.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 (239) hide show
  1. package/CLAUDE.md +22 -0
  2. package/dist/actions/attention.d.ts +24 -0
  3. package/dist/actions/attention.js +94 -0
  4. package/dist/actions/collapse.js +29 -15
  5. package/dist/actions/floating.d.ts +53 -0
  6. package/dist/actions/floating.js +158 -0
  7. package/dist/actions/listNav.js +137 -108
  8. package/dist/actions/railNav.js +89 -72
  9. package/dist/actions/staggerEntrance.d.ts +28 -0
  10. package/dist/actions/staggerEntrance.js +71 -0
  11. package/dist/actions/tooltip.d.ts +28 -0
  12. package/dist/actions/tooltip.js +186 -0
  13. package/dist/assets/sounds/README.md +47 -0
  14. package/dist/assets/sounds/error.d.ts +1 -0
  15. package/dist/assets/sounds/error.js +4 -0
  16. package/dist/assets/sounds/notify.d.ts +1 -0
  17. package/dist/assets/sounds/notify.js +4 -0
  18. package/dist/assets/sounds/pop.d.ts +1 -0
  19. package/dist/assets/sounds/pop.js +4 -0
  20. package/dist/assets/sounds/send.d.ts +1 -0
  21. package/dist/assets/sounds/send.js +4 -0
  22. package/dist/assets/sounds/success.d.ts +1 -0
  23. package/dist/assets/sounds/success.js +4 -0
  24. package/dist/assets/sounds/toggle.d.ts +1 -0
  25. package/dist/assets/sounds/toggle.js +4 -0
  26. package/dist/components/AnimatedNumber.svelte +112 -0
  27. package/dist/components/AnimatedNumber.svelte.d.ts +8 -0
  28. package/dist/components/Badge.svelte +75 -4
  29. package/dist/components/Badge.svelte.d.ts +6 -1
  30. package/dist/components/Button.svelte +196 -21
  31. package/dist/components/Button.svelte.d.ts +10 -1
  32. package/dist/components/Carousel.svelte +265 -0
  33. package/dist/components/Carousel.svelte.d.ts +21 -0
  34. package/dist/components/ChipInput.svelte +63 -3
  35. package/dist/components/Collapse.svelte +70 -14
  36. package/dist/components/Collapse.svelte.d.ts +11 -0
  37. package/dist/components/ColorSelector.svelte +21 -24
  38. package/dist/components/CommandPalette.svelte +475 -0
  39. package/dist/components/CommandPalette.svelte.d.ts +3 -0
  40. package/dist/components/ContextMenu.svelte +9 -73
  41. package/dist/components/CopyButton.svelte +156 -0
  42. package/dist/components/CopyButton.svelte.d.ts +12 -0
  43. package/dist/components/HoldToConfirm.svelte +183 -0
  44. package/dist/components/HoldToConfirm.svelte.d.ts +11 -0
  45. package/dist/components/KeyboardShortcutsOverlay.svelte +54 -8
  46. package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +3 -0
  47. package/dist/components/PasswordMeter.svelte +87 -0
  48. package/dist/components/PasswordMeter.svelte.d.ts +8 -0
  49. package/dist/components/PinInput.svelte +186 -0
  50. package/dist/components/PinInput.svelte.d.ts +13 -0
  51. package/dist/components/QuantityStepper.svelte +185 -0
  52. package/dist/components/QuantityStepper.svelte.d.ts +12 -0
  53. package/dist/components/Skeleton.svelte +123 -0
  54. package/dist/components/Skeleton.svelte.d.ts +12 -0
  55. package/dist/components/SpeechForm.svelte +37 -0
  56. package/dist/components/StatusBadge.svelte +31 -3
  57. package/dist/components/StatusBadge.svelte.d.ts +0 -5
  58. package/dist/components/Tabs.svelte +270 -0
  59. package/dist/components/Tabs.svelte.d.ts +15 -0
  60. package/dist/components/TextInput.svelte +138 -38
  61. package/dist/components/TextInput.svelte.d.ts +9 -1
  62. package/dist/components/VoicePlayer.svelte +51 -0
  63. package/dist/components/basic/Alert.svelte +36 -0
  64. package/dist/components/basic/Alert.svelte.d.ts +9 -0
  65. package/dist/components/basic/Breadcrumb.svelte +27 -0
  66. package/dist/components/basic/Breadcrumb.svelte.d.ts +11 -0
  67. package/dist/components/basic/ButtonGroup.svelte +15 -0
  68. package/dist/components/basic/ButtonGroup.svelte.d.ts +8 -0
  69. package/dist/components/basic/Checkbox.svelte +85 -0
  70. package/dist/components/basic/Checkbox.svelte.d.ts +15 -0
  71. package/dist/components/basic/Empty.svelte +17 -0
  72. package/dist/components/basic/Empty.svelte.d.ts +8 -0
  73. package/dist/components/basic/Kbd.svelte +16 -0
  74. package/dist/components/basic/Kbd.svelte.d.ts +8 -0
  75. package/dist/components/basic/Pagination.svelte +104 -0
  76. package/dist/components/basic/Pagination.svelte.d.ts +12 -0
  77. package/dist/components/basic/RadioGroup.svelte +71 -0
  78. package/dist/components/basic/RadioGroup.svelte.d.ts +18 -0
  79. package/dist/components/basic/Separator.svelte +19 -0
  80. package/dist/components/basic/Separator.svelte.d.ts +8 -0
  81. package/dist/components/basic/Slider.svelte +72 -0
  82. package/dist/components/basic/Slider.svelte.d.ts +17 -0
  83. package/dist/components/basic/Switch.svelte +88 -0
  84. package/dist/components/basic/Switch.svelte.d.ts +14 -0
  85. package/dist/components/basic/Toggle.svelte +43 -0
  86. package/dist/components/basic/Toggle.svelte.d.ts +14 -0
  87. package/dist/components/graph/GraphCanvas.svelte +103 -0
  88. package/dist/components/graph/GraphCanvas.svelte.d.ts +22 -0
  89. package/dist/components/graph/JatuiNode.svelte +128 -0
  90. package/dist/components/graph/JatuiNode.svelte.d.ts +14 -0
  91. package/dist/components/graph/theme.d.ts +27 -0
  92. package/dist/components/graph/theme.js +136 -0
  93. package/dist/components/markup.js +62 -59
  94. package/dist/components/messaging/MessageItem.svelte +92 -0
  95. package/dist/components/messaging/MessageItem.svelte.d.ts +5 -0
  96. package/dist/components/messaging/TypingIndicator.svelte +63 -0
  97. package/dist/components/messaging/TypingIndicator.svelte.d.ts +7 -0
  98. package/dist/components/pipeline/PipelineColumn.svelte +44 -3
  99. package/dist/components/progress/ProgressBar.svelte +189 -0
  100. package/dist/components/progress/ProgressBar.svelte.d.ts +17 -0
  101. package/dist/components/progress/ProgressRing.svelte +138 -0
  102. package/dist/components/progress/ProgressRing.svelte.d.ts +12 -0
  103. package/dist/components/progress/Steps.svelte +195 -0
  104. package/dist/components/progress/Steps.svelte.d.ts +14 -0
  105. package/dist/components/session-nav/transcriptModel.js +66 -49
  106. package/dist/components/shell/NavigationMenu.svelte +422 -0
  107. package/dist/components/shell/NavigationMenu.svelte.d.ts +43 -0
  108. package/dist/components/shell/Sidebar.svelte +276 -0
  109. package/dist/components/shell/Sidebar.svelte.d.ts +32 -0
  110. package/dist/components/shell/SidebarGroup.svelte +180 -0
  111. package/dist/components/shell/SidebarGroup.svelte.d.ts +19 -0
  112. package/dist/components/shell/SidebarItem.svelte +170 -0
  113. package/dist/components/shell/SidebarItem.svelte.d.ts +24 -0
  114. package/dist/components/shell/shell.d.ts +30 -0
  115. package/dist/components/shell/shell.js +65 -0
  116. package/dist/components/table/DataTable.svelte +364 -0
  117. package/dist/components/table/DataTable.svelte.d.ts +4 -0
  118. package/dist/components/table/flexRender.d.ts +31 -0
  119. package/dist/components/table/flexRender.js +32 -0
  120. package/dist/components/table/types.d.ts +28 -0
  121. package/dist/components/table/types.js +1 -0
  122. package/dist/components/toast/ToastHost.svelte +21 -0
  123. package/dist/components/toast/ToastHost.svelte.d.ts +3 -0
  124. package/dist/components/toast/ToastItem.svelte +287 -0
  125. package/dist/components/toast/ToastItem.svelte.d.ts +9 -0
  126. package/dist/data/emojis.js +4 -4
  127. package/dist/dnd/autoScroll.js +12 -10
  128. package/dist/dnd/createDndBoard.svelte.js +110 -76
  129. package/dist/dnd/createDndBoard.test.js +161 -85
  130. package/dist/dnd/draggable.js +23 -15
  131. package/dist/dnd/dropTarget.js +29 -15
  132. package/dist/dnd/index.d.ts +0 -1
  133. package/dist/dnd/index.js +0 -1
  134. package/dist/dnd/types.d.ts +0 -9
  135. package/dist/dnd/types.js +14 -2
  136. package/dist/index.d.ts +60 -6
  137. package/dist/index.js +73 -6
  138. package/dist/showcase/AnimatedBeam.svelte +183 -0
  139. package/dist/showcase/AnimatedBeam.svelte.d.ts +26 -0
  140. package/dist/showcase/AuroraDrift.svelte +74 -0
  141. package/dist/showcase/AuroraDrift.svelte.d.ts +9 -0
  142. package/dist/showcase/BentoCard.svelte +50 -0
  143. package/dist/showcase/BentoCard.svelte.d.ts +14 -0
  144. package/dist/showcase/BentoGrid.svelte +43 -0
  145. package/dist/showcase/BentoGrid.svelte.d.ts +12 -0
  146. package/dist/showcase/BorderBeam.svelte +79 -0
  147. package/dist/showcase/BorderBeam.svelte.d.ts +12 -0
  148. package/dist/showcase/ClipWipe.svelte +82 -0
  149. package/dist/showcase/ClipWipe.svelte.d.ts +12 -0
  150. package/dist/showcase/Confetti.svelte +71 -0
  151. package/dist/showcase/Confetti.svelte.d.ts +10 -0
  152. package/dist/showcase/CursorSpotlight.svelte +85 -0
  153. package/dist/showcase/CursorSpotlight.svelte.d.ts +9 -0
  154. package/dist/showcase/DeviceMock.svelte +186 -0
  155. package/dist/showcase/DeviceMock.svelte.d.ts +11 -0
  156. package/dist/showcase/Dock.svelte +123 -0
  157. package/dist/showcase/Dock.svelte.d.ts +17 -0
  158. package/dist/showcase/FlipCard.svelte +103 -0
  159. package/dist/showcase/FlipCard.svelte.d.ts +10 -0
  160. package/dist/showcase/FocusReveal.svelte +83 -0
  161. package/dist/showcase/FocusReveal.svelte.d.ts +11 -0
  162. package/dist/showcase/Globe.svelte +202 -0
  163. package/dist/showcase/Globe.svelte.d.ts +16 -0
  164. package/dist/showcase/KenBurns.svelte +105 -0
  165. package/dist/showcase/KenBurns.svelte.d.ts +13 -0
  166. package/dist/showcase/Marquee.svelte +89 -0
  167. package/dist/showcase/Marquee.svelte.d.ts +9 -0
  168. package/dist/showcase/ParallaxTilt.svelte +98 -0
  169. package/dist/showcase/ParallaxTilt.svelte.d.ts +10 -0
  170. package/dist/showcase/ScrambleText.svelte +98 -0
  171. package/dist/showcase/ScrambleText.svelte.d.ts +11 -0
  172. package/dist/showcase/ShineSweep.svelte +81 -0
  173. package/dist/showcase/ShineSweep.svelte.d.ts +9 -0
  174. package/dist/showcase/Terminal.svelte +230 -0
  175. package/dist/showcase/Terminal.svelte.d.ts +18 -0
  176. package/dist/showcase/TextSplitReveal.svelte +146 -0
  177. package/dist/showcase/TextSplitReveal.svelte.d.ts +13 -0
  178. package/dist/showcase/TextWave.svelte +55 -0
  179. package/dist/showcase/TextWave.svelte.d.ts +8 -0
  180. package/dist/showcase/TypewriterText.svelte +130 -0
  181. package/dist/showcase/TypewriterText.svelte.d.ts +9 -0
  182. package/dist/showcase/backdrop/GrainGradient.svelte +126 -0
  183. package/dist/showcase/backdrop/GrainGradient.svelte.d.ts +23 -0
  184. package/dist/showcase/backdrop/MeshGradient.svelte +104 -0
  185. package/dist/showcase/backdrop/MeshGradient.svelte.d.ts +20 -0
  186. package/dist/showcase/backdrop/Metaballs.svelte +116 -0
  187. package/dist/showcase/backdrop/Metaballs.svelte.d.ts +18 -0
  188. package/dist/showcase/backdrop/NeuroNoise.svelte +115 -0
  189. package/dist/showcase/backdrop/NeuroNoise.svelte.d.ts +20 -0
  190. package/dist/showcase/backdrop/ShowcaseBackdrop.svelte +48 -0
  191. package/dist/showcase/backdrop/ShowcaseBackdrop.svelte.d.ts +12 -0
  192. package/dist/showcase/generative/GenerativeBackdrop.svelte +234 -0
  193. package/dist/showcase/generative/GenerativeBackdrop.svelte.d.ts +9 -0
  194. package/dist/showcase/generative/intent.d.ts +7 -0
  195. package/dist/showcase/generative/intent.js +67 -0
  196. package/dist/showcase/generative/manifest.d.ts +9 -0
  197. package/dist/showcase/generative/manifest.js +97 -0
  198. package/dist/showcase/generative/types.d.ts +48 -0
  199. package/dist/showcase/generative/types.js +8 -0
  200. package/dist/showcase/index.d.ts +36 -0
  201. package/dist/showcase/index.js +46 -0
  202. package/dist/showcase/scroll/SmoothScroll.svelte +49 -0
  203. package/dist/showcase/scroll/SmoothScroll.svelte.d.ts +12 -0
  204. package/dist/showcase/scroll/scrollProgress.d.ts +24 -0
  205. package/dist/showcase/scroll/scrollProgress.js +65 -0
  206. package/dist/showcase/scroll/scrollReveal.d.ts +30 -0
  207. package/dist/showcase/scroll/scrollReveal.js +70 -0
  208. package/dist/stores/commandPalette.svelte.d.ts +24 -0
  209. package/dist/stores/commandPalette.svelte.js +82 -0
  210. package/dist/stores/confirmDialog.svelte.js +5 -5
  211. package/dist/stores/inputDialog.svelte.js +5 -5
  212. package/dist/stores/toast.svelte.d.ts +28 -0
  213. package/dist/stores/toast.svelte.js +33 -0
  214. package/dist/styles/motion.css +46 -0
  215. package/dist/styles/tokens.css +31 -0
  216. package/dist/transitions/glide.d.ts +31 -0
  217. package/dist/transitions/glide.js +58 -0
  218. package/dist/types/booking.js +4 -4
  219. package/dist/types/comments.js +2 -2
  220. package/dist/types/messaging.js +3 -3
  221. package/dist/types/pipeline.js +2 -2
  222. package/dist/utils/currency.js +4 -2
  223. package/dist/utils/daisyuiColors.js +27 -25
  224. package/dist/utils/dateFormatters.d.ts +20 -0
  225. package/dist/utils/dateFormatters.js +65 -44
  226. package/dist/utils/googleMapsLoader.js +100 -46
  227. package/dist/utils/mentionParser.js +30 -30
  228. package/dist/utils/phone.js +27 -21
  229. package/dist/utils/phoneFormat.js +9 -9
  230. package/dist/utils/sound.d.ts +6 -0
  231. package/dist/utils/sound.js +113 -0
  232. package/dist/utils/splitText.d.ts +25 -0
  233. package/dist/utils/splitText.js +94 -0
  234. package/dist/utils/taskUtils.js +1 -1
  235. package/dist/utils/themeWipe.d.ts +21 -0
  236. package/dist/utils/themeWipe.js +94 -0
  237. package/dist/utils/viewTransition.d.ts +23 -0
  238. package/dist/utils/viewTransition.js +75 -0
  239. package/package.json +56 -4
@@ -0,0 +1,83 @@
1
+ // after animista.net (Ana Travas), re-authored on jatui motion tokens
2
+ <script lang="ts">
3
+ import type { Snippet } from 'svelte';
4
+ import { onMount } from 'svelte';
5
+
6
+ type TriggerMode = 'mount' | 'intersect';
7
+
8
+ interface Props {
9
+ triggerMode?: TriggerMode;
10
+ durationMs?: number;
11
+ class?: string;
12
+ children: Snippet;
13
+ }
14
+
15
+ let {
16
+ triggerMode = 'mount',
17
+ durationMs = 800,
18
+ class: className = '',
19
+ children,
20
+ }: Props = $props();
21
+
22
+ let reducedMotion = $state(false);
23
+ let revealed = $state(false);
24
+ let el: HTMLDivElement | undefined = $state();
25
+
26
+ onMount(() => {
27
+ reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
28
+
29
+ if (reducedMotion) {
30
+ revealed = true;
31
+ return;
32
+ }
33
+
34
+ if (triggerMode === 'mount') {
35
+ requestAnimationFrame(() => {
36
+ revealed = true;
37
+ });
38
+ } else {
39
+ const observer = new IntersectionObserver(
40
+ (entries) => {
41
+ for (const entry of entries) {
42
+ if (entry.intersectionRatio >= 0.5) {
43
+ revealed = true;
44
+ observer.disconnect();
45
+ }
46
+ }
47
+ },
48
+ { threshold: 0.5 }
49
+ );
50
+
51
+ if (el) observer.observe(el);
52
+
53
+ return () => observer.disconnect();
54
+ }
55
+ });
56
+ </script>
57
+
58
+ <div
59
+ bind:this={el}
60
+ class="focus-reveal-root {className}"
61
+ style:filter={reducedMotion || revealed ? 'blur(0px)' : 'blur(8px)'}
62
+ style:opacity={reducedMotion || revealed ? '1' : '0.6'}
63
+ style:transition={reducedMotion
64
+ ? 'none'
65
+ : `filter ${durationMs}ms var(--motion-glide), opacity ${durationMs}ms var(--motion-glide)`}
66
+ >
67
+ {@render children()}
68
+ </div>
69
+
70
+ <style>
71
+ .focus-reveal-root {
72
+ will-change: filter, opacity;
73
+ }
74
+
75
+ @media (prefers-reduced-motion: reduce) {
76
+ .focus-reveal-root {
77
+ filter: none !important;
78
+ opacity: 1 !important;
79
+ transition: none !important;
80
+ will-change: auto;
81
+ }
82
+ }
83
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ type TriggerMode = 'mount' | 'intersect';
3
+ interface Props {
4
+ triggerMode?: TriggerMode;
5
+ durationMs?: number;
6
+ class?: string;
7
+ children: Snippet;
8
+ }
9
+ declare const FocusReveal: import("svelte").Component<Props, {}, "">;
10
+ type FocusReveal = ReturnType<typeof FocusReveal>;
11
+ export default FocusReveal;
@@ -0,0 +1,202 @@
1
+ <script lang="ts">
2
+ import createGlobe from 'cobe';
3
+ import type { Globe, Marker } from 'cobe';
4
+ import { getDaisyUIColor, watchThemeChanges } from '../utils/daisyuiColors';
5
+
6
+ interface Props {
7
+ markers?: Marker[];
8
+ size?: number;
9
+ autoRotateSpeed?: number;
10
+ /** Override globe colors. Defaults to DaisyUI theme primary/neutral/glow. */
11
+ colors?: {
12
+ base?: [number, number, number];
13
+ marker?: [number, number, number];
14
+ glow?: [number, number, number];
15
+ };
16
+ class?: string;
17
+ }
18
+
19
+ let {
20
+ markers = [],
21
+ size = 600,
22
+ autoRotateSpeed = 0.005,
23
+ colors,
24
+ class: className = '',
25
+ }: Props = $props();
26
+
27
+ let canvas: HTMLCanvasElement | undefined = $state();
28
+ let globe: Globe | undefined;
29
+ let phi = 0;
30
+ let theta = 0.3;
31
+ let animFrame = 0;
32
+ let isDragging = false;
33
+ let lastPointerX = 0;
34
+ let lastPointerY = 0;
35
+ let velocityX = 0;
36
+ let velocityY = 0;
37
+ let paused = false;
38
+
39
+ const prefersReducedMotion =
40
+ typeof window !== 'undefined'
41
+ ? window.matchMedia('(prefers-reduced-motion: reduce)').matches
42
+ : false;
43
+
44
+ // Convert a CSS color string to a cobe [r, g, b] tuple (0–1 range).
45
+ function cssToRgb(css: string): [number, number, number] {
46
+ try {
47
+ const c = document.createElement('canvas');
48
+ c.width = 1;
49
+ c.height = 1;
50
+ const ctx = c.getContext('2d');
51
+ if (!ctx) return [0.5, 0.5, 0.5];
52
+ ctx.fillStyle = css;
53
+ ctx.fillRect(0, 0, 1, 1);
54
+ const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data;
55
+ return [r / 255, g / 255, b / 255];
56
+ } catch {
57
+ return [0.5, 0.5, 0.5];
58
+ }
59
+ }
60
+
61
+ function resolveColors() {
62
+ return {
63
+ base: colors?.base ?? cssToRgb(getDaisyUIColor('neutral')),
64
+ marker: colors?.marker ?? cssToRgb(getDaisyUIColor('primary')),
65
+ glow: colors?.glow ?? cssToRgb(getDaisyUIColor('primary')),
66
+ };
67
+ }
68
+
69
+ function tick() {
70
+ if (paused || !globe) {
71
+ animFrame = requestAnimationFrame(tick);
72
+ return;
73
+ }
74
+
75
+ if (!isDragging) {
76
+ if (!prefersReducedMotion) {
77
+ phi += autoRotateSpeed;
78
+ }
79
+ if (Math.abs(velocityX) > 0.0001 || Math.abs(velocityY) > 0.0001) {
80
+ phi += velocityX;
81
+ theta = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, theta + velocityY));
82
+ velocityX *= 0.92;
83
+ velocityY *= 0.92;
84
+ }
85
+ }
86
+
87
+ globe.update({ phi, theta });
88
+ animFrame = requestAnimationFrame(tick);
89
+ }
90
+
91
+ function startGlobe() {
92
+ if (!canvas) return;
93
+ cancelAnimationFrame(animFrame);
94
+ globe?.destroy();
95
+ globe = undefined;
96
+
97
+ const c = resolveColors();
98
+ const dpr = window.devicePixelRatio ?? 1;
99
+
100
+ globe = createGlobe(canvas, {
101
+ width: size * dpr,
102
+ height: size * dpr,
103
+ phi,
104
+ theta,
105
+ dark: 1,
106
+ diffuse: 1.2,
107
+ mapSamples: 16000,
108
+ mapBrightness: 6,
109
+ baseColor: c.base,
110
+ markerColor: c.marker,
111
+ glowColor: c.glow,
112
+ markers,
113
+ devicePixelRatio: dpr,
114
+ opacity: 1,
115
+ });
116
+
117
+ animFrame = requestAnimationFrame(tick);
118
+ }
119
+
120
+ $effect(() => {
121
+ if (!canvas) return;
122
+
123
+ startGlobe();
124
+
125
+ const unwatchTheme = watchThemeChanges(() => {
126
+ startGlobe();
127
+ });
128
+
129
+ const observer = new IntersectionObserver(
130
+ ([entry]) => {
131
+ paused = !entry.isIntersecting;
132
+ },
133
+ { threshold: 0.1 }
134
+ );
135
+ observer.observe(canvas);
136
+
137
+ return () => {
138
+ cancelAnimationFrame(animFrame);
139
+ globe?.destroy();
140
+ globe = undefined;
141
+ observer.disconnect();
142
+ unwatchTheme();
143
+ };
144
+ });
145
+
146
+ function onPointerDown(e: PointerEvent) {
147
+ isDragging = true;
148
+ lastPointerX = e.clientX;
149
+ lastPointerY = e.clientY;
150
+ velocityX = 0;
151
+ velocityY = 0;
152
+ (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
153
+ }
154
+
155
+ function onPointerMove(e: PointerEvent) {
156
+ if (!isDragging) return;
157
+ const dx = e.clientX - lastPointerX;
158
+ const dy = e.clientY - lastPointerY;
159
+ const sensitivity = 0.005;
160
+ velocityX = dx * sensitivity;
161
+ velocityY = dy * sensitivity;
162
+ phi += velocityX;
163
+ theta = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, theta + velocityY));
164
+ lastPointerX = e.clientX;
165
+ lastPointerY = e.clientY;
166
+ }
167
+
168
+ function onPointerUp(_e: PointerEvent) {
169
+ isDragging = false;
170
+ }
171
+ </script>
172
+
173
+ <div
174
+ class="globe-root {className}"
175
+ style="width:{size}px;height:{size}px;"
176
+ role="img"
177
+ aria-label="Interactive globe"
178
+ >
179
+ <canvas
180
+ bind:this={canvas}
181
+ style="width:{size}px;height:{size}px;cursor:{isDragging ? 'grabbing' : 'grab'};"
182
+ onpointerdown={onPointerDown}
183
+ onpointermove={onPointerMove}
184
+ onpointerup={onPointerUp}
185
+ onpointercancel={onPointerUp}
186
+ ></canvas>
187
+ </div>
188
+
189
+ <style>
190
+ .globe-root {
191
+ display: block;
192
+ position: relative;
193
+ overflow: hidden;
194
+ border-radius: 50%;
195
+ user-select: none;
196
+ touch-action: none;
197
+ }
198
+
199
+ canvas {
200
+ display: block;
201
+ }
202
+ </style>
@@ -0,0 +1,16 @@
1
+ import type { Globe, Marker } from 'cobe';
2
+ interface Props {
3
+ markers?: Marker[];
4
+ size?: number;
5
+ autoRotateSpeed?: number;
6
+ /** Override globe colors. Defaults to DaisyUI theme primary/neutral/glow. */
7
+ colors?: {
8
+ base?: [number, number, number];
9
+ marker?: [number, number, number];
10
+ glow?: [number, number, number];
11
+ };
12
+ class?: string;
13
+ }
14
+ declare const Globe: import("svelte").Component<Props, {}, "">;
15
+ type Globe = ReturnType<typeof Globe>;
16
+ export default Globe;
@@ -0,0 +1,105 @@
1
+ // after animista.net (Ana Travas), re-authored on jatui motion tokens
2
+ <script lang="ts">
3
+ import type { Snippet } from 'svelte';
4
+ import { onMount } from 'svelte';
5
+
6
+ type Direction =
7
+ | 'top'
8
+ | 'bottom'
9
+ | 'left'
10
+ | 'right'
11
+ | 'top-left'
12
+ | 'top-right'
13
+ | 'bottom-left'
14
+ | 'bottom-right';
15
+
16
+ type LoopMode = 'alternate' | 'hold';
17
+
18
+ interface Props {
19
+ direction?: Direction;
20
+ durationS?: number;
21
+ loop?: LoopMode;
22
+ class?: string;
23
+ children?: Snippet;
24
+ }
25
+
26
+ let {
27
+ direction = 'top-right',
28
+ durationS = 20,
29
+ loop = 'alternate',
30
+ class: className = '',
31
+ children,
32
+ }: Props = $props();
33
+
34
+ let reducedMotion = $state(false);
35
+
36
+ onMount(() => {
37
+ reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
38
+ });
39
+
40
+ // Each compass direction maps to a translate endpoint at scale 1.12
41
+ // The pan shifts the visible crop slightly while the image zooms in.
42
+ const translateMap: Record<Direction, string> = {
43
+ top: 'translate(0%, -4%)',
44
+ bottom: 'translate(0%, 4%)',
45
+ left: 'translate(-4%, 0%)',
46
+ right: 'translate(4%, 0%)',
47
+ 'top-left': 'translate(-3%, -3%)',
48
+ 'top-right': 'translate(3%, -3%)',
49
+ 'bottom-left': 'translate(-3%, 3%)',
50
+ 'bottom-right': 'translate(3%, 3%)',
51
+ };
52
+
53
+ const endTransform = $derived(`scale(1.12) ${translateMap[direction]}`);
54
+ const iterationCount = $derived(loop === 'alternate' ? 'infinite' : '1');
55
+ const fillMode = $derived(loop === 'hold' ? 'forwards' : 'none');
56
+ const alternateDir = $derived(loop === 'alternate' ? 'alternate' : 'normal');
57
+ </script>
58
+
59
+ <div class="ken-burns-root {className}" aria-hidden="true">
60
+ <div
61
+ class="ken-burns-inner"
62
+ style:animation-name={reducedMotion ? 'none' : 'ken-burns-zoom'}
63
+ style:animation-duration="{durationS}s"
64
+ style:animation-timing-function="ease-in-out"
65
+ style:animation-iteration-count={reducedMotion ? '1' : iterationCount}
66
+ style:animation-direction={reducedMotion ? 'normal' : alternateDir}
67
+ style:animation-fill-mode={reducedMotion ? 'none' : fillMode}
68
+ style:--kb-end-transform={endTransform}
69
+ >
70
+ {#if children}
71
+ {@render children()}
72
+ {/if}
73
+ </div>
74
+ </div>
75
+
76
+ <style>
77
+ .ken-burns-root {
78
+ overflow: hidden;
79
+ position: relative;
80
+ }
81
+
82
+ .ken-burns-inner {
83
+ width: 100%;
84
+ height: 100%;
85
+ transform-origin: center center;
86
+ will-change: transform;
87
+ pointer-events: auto;
88
+ }
89
+
90
+ @keyframes ken-burns-zoom {
91
+ 0% {
92
+ transform: scale(1) translate(0, 0);
93
+ }
94
+ 100% {
95
+ transform: var(--kb-end-transform);
96
+ }
97
+ }
98
+
99
+ @media (prefers-reduced-motion: reduce) {
100
+ .ken-burns-inner {
101
+ animation: none !important;
102
+ will-change: auto;
103
+ }
104
+ }
105
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Direction = 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
3
+ type LoopMode = 'alternate' | 'hold';
4
+ interface Props {
5
+ direction?: Direction;
6
+ durationS?: number;
7
+ loop?: LoopMode;
8
+ class?: string;
9
+ children?: Snippet;
10
+ }
11
+ declare const KenBurns: import("svelte").Component<Props, {}, "">;
12
+ type KenBurns = ReturnType<typeof KenBurns>;
13
+ export default KenBurns;
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import { onDestroy } from 'svelte';
3
+
4
+ interface Props {
5
+ speed?: number;
6
+ pauseOnHover?: boolean;
7
+ class?: string;
8
+ children: import('svelte').Snippet;
9
+ }
10
+
11
+ let {
12
+ speed = 14,
13
+ pauseOnHover = true,
14
+ class: className = '',
15
+ children,
16
+ }: Props = $props();
17
+
18
+ let paused = $state(false);
19
+
20
+ function handleMouseEnter() {
21
+ if (pauseOnHover) paused = true;
22
+ }
23
+
24
+ function handleMouseLeave() {
25
+ if (pauseOnHover) paused = false;
26
+ }
27
+
28
+ onDestroy(() => {
29
+ paused = false;
30
+ });
31
+ </script>
32
+
33
+ <div
34
+ class="marquee-wrapper {className}"
35
+ style="--marquee-speed: {speed}s;"
36
+ onmouseenter={handleMouseEnter}
37
+ onmouseleave={handleMouseLeave}
38
+ aria-label="Scrolling content"
39
+ >
40
+ <div
41
+ class="marquee-track"
42
+ class:paused
43
+ >
44
+ <div class="marquee-content" aria-hidden="false">
45
+ {@render children()}
46
+ </div>
47
+ <div class="marquee-content" aria-hidden="true">
48
+ {@render children()}
49
+ </div>
50
+ </div>
51
+ </div>
52
+
53
+ <style>
54
+ @keyframes marquee-scroll {
55
+ from {
56
+ transform: translateX(0);
57
+ }
58
+ to {
59
+ transform: translateX(-50%);
60
+ }
61
+ }
62
+
63
+ .marquee-wrapper {
64
+ overflow: hidden;
65
+ mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
66
+ -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
67
+ }
68
+
69
+ .marquee-track {
70
+ display: flex;
71
+ width: max-content;
72
+ animation: marquee-scroll var(--marquee-speed, 14s) linear infinite;
73
+ }
74
+
75
+ .marquee-track.paused {
76
+ animation-play-state: paused;
77
+ }
78
+
79
+ .marquee-content {
80
+ display: flex;
81
+ flex-shrink: 0;
82
+ }
83
+
84
+ @media (prefers-reduced-motion: reduce) {
85
+ .marquee-track {
86
+ animation: none;
87
+ }
88
+ }
89
+ </style>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ speed?: number;
3
+ pauseOnHover?: boolean;
4
+ class?: string;
5
+ children: import('svelte').Snippet;
6
+ }
7
+ declare const Marquee: import("svelte").Component<Props, {}, "">;
8
+ type Marquee = ReturnType<typeof Marquee>;
9
+ export default Marquee;
@@ -0,0 +1,98 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { onMount } from 'svelte';
4
+
5
+ interface Props {
6
+ maxTilt?: number;
7
+ glare?: boolean;
8
+ class?: string;
9
+ children?: Snippet;
10
+ }
11
+
12
+ let { maxTilt = 16, glare = false, class: className = '', children }: Props = $props();
13
+
14
+ let outerEl = $state<HTMLDivElement | null>(null);
15
+ let transform = $state('');
16
+ let glareX = $state(50);
17
+ let glareY = $state(50);
18
+ let hasFinePointer = $state(false);
19
+ let reducedMotion = $state(false);
20
+
21
+ onMount(() => {
22
+ hasFinePointer = window.matchMedia('(pointer: fine)').matches;
23
+ reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
24
+ });
25
+
26
+ function onMouseMove(e: MouseEvent) {
27
+ if (!outerEl || !hasFinePointer || reducedMotion) return;
28
+ const rect = outerEl.getBoundingClientRect();
29
+ const px = (e.clientX - rect.left) / rect.width;
30
+ const py = (e.clientY - rect.top) / rect.height;
31
+ const rotX = (py - 0.5) * -maxTilt;
32
+ const rotY = (px - 0.5) * maxTilt;
33
+ transform = `rotateX(${rotX}deg) rotateY(${rotY}deg)`;
34
+ glareX = px * 100;
35
+ glareY = py * 100;
36
+ }
37
+
38
+ function onMouseLeave() {
39
+ transform = '';
40
+ glareX = 50;
41
+ glareY = 50;
42
+ }
43
+ </script>
44
+
45
+ <div
46
+ bind:this={outerEl}
47
+ class="parallax-tilt-outer {className}"
48
+ onmousemove={onMouseMove}
49
+ onmouseleave={onMouseLeave}
50
+ role="presentation"
51
+ >
52
+ <div class="parallax-tilt-card" style="transform: {transform};">
53
+ {#if glare && hasFinePointer && !reducedMotion}
54
+ <div
55
+ class="parallax-tilt-glare"
56
+ style="background: radial-gradient(circle at {glareX}% {glareY}%, rgba(255,255,255,0.25) 0%, transparent 65%);"
57
+ aria-hidden="true"
58
+ ></div>
59
+ {/if}
60
+ {#if children}
61
+ {@render children()}
62
+ {/if}
63
+ </div>
64
+ </div>
65
+
66
+ <style>
67
+ .parallax-tilt-outer {
68
+ perspective: 800px;
69
+ display: inline-block;
70
+ }
71
+
72
+ .parallax-tilt-card {
73
+ position: relative;
74
+ transform-style: preserve-3d;
75
+ transition: transform 0.15s ease-out;
76
+ will-change: transform;
77
+ }
78
+
79
+ .parallax-tilt-glare {
80
+ position: absolute;
81
+ inset: 0;
82
+ border-radius: inherit;
83
+ pointer-events: none;
84
+ z-index: 1;
85
+ }
86
+
87
+ @media (prefers-reduced-motion: reduce) {
88
+ .parallax-tilt-card {
89
+ transform: none !important;
90
+ transition: none;
91
+ will-change: auto;
92
+ }
93
+
94
+ .parallax-tilt-glare {
95
+ display: none;
96
+ }
97
+ }
98
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ maxTilt?: number;
4
+ glare?: boolean;
5
+ class?: string;
6
+ children?: Snippet;
7
+ }
8
+ declare const ParallaxTilt: import("svelte").Component<Props, {}, "">;
9
+ type ParallaxTilt = ReturnType<typeof ParallaxTilt>;
10
+ export default ParallaxTilt;