@moonarc/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.
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/package.json +228 -0
- package/src/components/Accordion.astro +110 -0
- package/src/components/Accordion.meta.ts +33 -0
- package/src/components/AnimatedBeam.astro +217 -0
- package/src/components/AnimatedBeam.meta.ts +39 -0
- package/src/components/AnimatedIcons.astro +193 -0
- package/src/components/AnimatedIcons.meta.ts +34 -0
- package/src/components/AnimatedList.astro +305 -0
- package/src/components/AnimatedList.meta.ts +36 -0
- package/src/components/AnimatedSelect.astro +227 -0
- package/src/components/AnimatedSelect.meta.ts +38 -0
- package/src/components/ArrowButton.astro +133 -0
- package/src/components/ArrowButton.meta.ts +32 -0
- package/src/components/Aurora.astro +188 -0
- package/src/components/Aurora.meta.ts +36 -0
- package/src/components/AvatarStack.astro +205 -0
- package/src/components/AvatarStack.meta.ts +37 -0
- package/src/components/BarGrow.astro +123 -0
- package/src/components/BarGrow.meta.ts +42 -0
- package/src/components/BorderBeam.astro +75 -0
- package/src/components/BorderBeam.meta.ts +33 -0
- package/src/components/BrowserFrame.astro +172 -0
- package/src/components/BrowserFrame.meta.ts +36 -0
- package/src/components/BubbleText.astro +90 -0
- package/src/components/BubbleText.meta.ts +38 -0
- package/src/components/CardStack.astro +79 -0
- package/src/components/CardStack.meta.ts +33 -0
- package/src/components/Carousel.astro +147 -0
- package/src/components/Carousel.meta.ts +35 -0
- package/src/components/CheckDraw.astro +159 -0
- package/src/components/CheckDraw.meta.ts +37 -0
- package/src/components/CircularText.astro +103 -0
- package/src/components/CircularText.meta.ts +38 -0
- package/src/components/CodeTabs.astro +213 -0
- package/src/components/CodeTabs.meta.ts +36 -0
- package/src/components/CommandPalette.astro +363 -0
- package/src/components/CommandPalette.meta.ts +40 -0
- package/src/components/Confetti.astro +143 -0
- package/src/components/Confetti.meta.ts +40 -0
- package/src/components/CopyButton.astro +189 -0
- package/src/components/CopyButton.meta.ts +41 -0
- package/src/components/CountUp.astro +134 -0
- package/src/components/CountUp.meta.ts +40 -0
- package/src/components/CountdownFlip.astro +244 -0
- package/src/components/CountdownFlip.meta.ts +39 -0
- package/src/components/CounterPreloader.astro +122 -0
- package/src/components/CounterPreloader.meta.ts +34 -0
- package/src/components/Cursor.astro +177 -0
- package/src/components/Cursor.meta.ts +37 -0
- package/src/components/CursorGrid.astro +113 -0
- package/src/components/CursorGrid.meta.ts +37 -0
- package/src/components/Curtain.astro +305 -0
- package/src/components/Curtain.meta.ts +38 -0
- package/src/components/Dialog.astro +156 -0
- package/src/components/Dialog.meta.ts +37 -0
- package/src/components/Dock.astro +193 -0
- package/src/components/Dock.meta.ts +35 -0
- package/src/components/DotPattern.astro +58 -0
- package/src/components/DotPattern.meta.ts +32 -0
- package/src/components/DottedMap.astro +153 -0
- package/src/components/DottedMap.meta.ts +38 -0
- package/src/components/Drawer.astro +196 -0
- package/src/components/Drawer.meta.ts +35 -0
- package/src/components/DynamicIsland.astro +122 -0
- package/src/components/DynamicIsland.meta.ts +35 -0
- package/src/components/FileTree.astro +207 -0
- package/src/components/FileTree.meta.ts +34 -0
- package/src/components/FilterGrid.astro +170 -0
- package/src/components/FilterGrid.meta.ts +38 -0
- package/src/components/FooterReveal.astro +54 -0
- package/src/components/FooterReveal.meta.ts +31 -0
- package/src/components/GlitchText.astro +145 -0
- package/src/components/GlitchText.meta.ts +39 -0
- package/src/components/Globe.astro +304 -0
- package/src/components/Globe.meta.ts +41 -0
- package/src/components/GlyphField.astro +363 -0
- package/src/components/GlyphField.meta.ts +53 -0
- package/src/components/GradientText.astro +63 -0
- package/src/components/GradientText.meta.ts +35 -0
- package/src/components/GridPattern.astro +55 -0
- package/src/components/GridPattern.meta.ts +32 -0
- package/src/components/HighlightMarker.astro +68 -0
- package/src/components/HighlightMarker.meta.ts +37 -0
- package/src/components/HorizontalScroll.astro +112 -0
- package/src/components/HorizontalScroll.meta.ts +34 -0
- package/src/components/HoverImageLinks.astro +219 -0
- package/src/components/HoverImageLinks.meta.ts +34 -0
- package/src/components/HoverVideo.astro +179 -0
- package/src/components/HoverVideo.meta.ts +37 -0
- package/src/components/ImageCompare.astro +212 -0
- package/src/components/ImageCompare.meta.ts +39 -0
- package/src/components/ImageTrail.astro +169 -0
- package/src/components/ImageTrail.meta.ts +36 -0
- package/src/components/Lightbox.astro +236 -0
- package/src/components/Lightbox.meta.ts +40 -0
- package/src/components/LinkPreview.astro +234 -0
- package/src/components/LinkPreview.meta.ts +39 -0
- package/src/components/LiquidGlass.astro +148 -0
- package/src/components/LiquidGlass.meta.ts +37 -0
- package/src/components/Magnetic.astro +92 -0
- package/src/components/Magnetic.meta.ts +31 -0
- package/src/components/Marquee.astro +165 -0
- package/src/components/Marquee.meta.ts +38 -0
- package/src/components/Meteors.astro +156 -0
- package/src/components/Meteors.meta.ts +36 -0
- package/src/components/Noise.astro +61 -0
- package/src/components/Noise.meta.ts +33 -0
- package/src/components/NumberFlow.astro +143 -0
- package/src/components/NumberFlow.meta.ts +42 -0
- package/src/components/Orb.astro +130 -0
- package/src/components/Orb.meta.ts +39 -0
- package/src/components/OrbitingCircles.astro +119 -0
- package/src/components/OrbitingCircles.meta.ts +36 -0
- package/src/components/OtpInput.astro +215 -0
- package/src/components/OtpInput.meta.ts +42 -0
- package/src/components/PageTransition.astro +121 -0
- package/src/components/PageTransition.meta.ts +33 -0
- package/src/components/Parallax.astro +69 -0
- package/src/components/Parallax.meta.ts +32 -0
- package/src/components/Particles.astro +210 -0
- package/src/components/Particles.meta.ts +37 -0
- package/src/components/PersistPlayer.astro +126 -0
- package/src/components/PersistPlayer.meta.ts +35 -0
- package/src/components/PhoneFrame.astro +161 -0
- package/src/components/PhoneFrame.meta.ts +35 -0
- package/src/components/PillNav.astro +170 -0
- package/src/components/PillNav.meta.ts +37 -0
- package/src/components/Popover.astro +95 -0
- package/src/components/Popover.meta.ts +34 -0
- package/src/components/PriceSwitch.astro +251 -0
- package/src/components/PriceSwitch.meta.ts +41 -0
- package/src/components/Probe.astro +84 -0
- package/src/components/Progress.astro +165 -0
- package/src/components/Progress.meta.ts +40 -0
- package/src/components/ProgressiveBlur.astro +95 -0
- package/src/components/ProgressiveBlur.meta.ts +36 -0
- package/src/components/PromptInput.astro +273 -0
- package/src/components/PromptInput.meta.ts +46 -0
- package/src/components/ReadingToc.astro +153 -0
- package/src/components/ReadingToc.meta.ts +34 -0
- package/src/components/RetroGrid.astro +84 -0
- package/src/components/RetroGrid.meta.ts +36 -0
- package/src/components/Reveal.astro +292 -0
- package/src/components/Reveal.meta.ts +48 -0
- package/src/components/Ripple.astro +94 -0
- package/src/components/Ripple.meta.ts +34 -0
- package/src/components/RotatingText.astro +170 -0
- package/src/components/RotatingText.meta.ts +35 -0
- package/src/components/ScrollExpand.astro +90 -0
- package/src/components/ScrollExpand.meta.ts +35 -0
- package/src/components/ScrollProgress.astro +73 -0
- package/src/components/ScrollProgress.meta.ts +32 -0
- package/src/components/ScrollScrub.astro +96 -0
- package/src/components/ScrollScrub.meta.ts +37 -0
- package/src/components/ShimmerButton.astro +109 -0
- package/src/components/ShimmerButton.meta.ts +37 -0
- package/src/components/ShinyText.astro +72 -0
- package/src/components/ShinyText.meta.ts +35 -0
- package/src/components/Skeleton.astro +76 -0
- package/src/components/Skeleton.meta.ts +32 -0
- package/src/components/Sparkline.astro +168 -0
- package/src/components/Sparkline.meta.ts +43 -0
- package/src/components/Spinner.astro +79 -0
- package/src/components/Spinner.meta.ts +33 -0
- package/src/components/SplitFlap.astro +157 -0
- package/src/components/SplitFlap.meta.ts +39 -0
- package/src/components/SplitText.astro +208 -0
- package/src/components/SplitText.meta.ts +50 -0
- package/src/components/Spotlight.astro +92 -0
- package/src/components/Spotlight.meta.ts +34 -0
- package/src/components/StaggerMenu.astro +301 -0
- package/src/components/StaggerMenu.meta.ts +39 -0
- package/src/components/StatefulButton.astro +148 -0
- package/src/components/StatefulButton.meta.ts +35 -0
- package/src/components/StickyBanner.astro +168 -0
- package/src/components/StickyBanner.meta.ts +45 -0
- package/src/components/StickyReveal.astro +256 -0
- package/src/components/StickyReveal.meta.ts +33 -0
- package/src/components/StrokeDraw.astro +110 -0
- package/src/components/StrokeDraw.meta.ts +43 -0
- package/src/components/Switch.astro +165 -0
- package/src/components/Switch.meta.ts +37 -0
- package/src/components/Tabs.astro +194 -0
- package/src/components/Tabs.meta.ts +47 -0
- package/src/components/TextRoll.astro +78 -0
- package/src/components/TextRoll.meta.ts +36 -0
- package/src/components/TextScramble.astro +107 -0
- package/src/components/TextScramble.meta.ts +35 -0
- package/src/components/ThemeScript.astro +17 -0
- package/src/components/ThemeToggle.astro +182 -0
- package/src/components/ThemeToggle.meta.ts +34 -0
- package/src/components/Tilt.astro +97 -0
- package/src/components/Tilt.meta.ts +34 -0
- package/src/components/Toast.astro +184 -0
- package/src/components/Toast.meta.ts +33 -0
- package/src/components/TracingBeam.astro +113 -0
- package/src/components/TracingBeam.meta.ts +34 -0
- package/src/components/Typewriter.astro +124 -0
- package/src/components/Typewriter.meta.ts +39 -0
- package/src/components/UnderlineHover.astro +61 -0
- package/src/components/UnderlineHover.meta.ts +34 -0
- package/src/components/VanishInput.astro +240 -0
- package/src/components/VanishInput.meta.ts +41 -0
- package/src/components/VideoDialog.astro +230 -0
- package/src/components/VideoDialog.meta.ts +40 -0
- package/src/components/WeightWave.astro +70 -0
- package/src/components/WeightWave.meta.ts +36 -0
- package/src/components/internal/DialogMorph.astro +97 -0
- package/src/components/internal/PromptInputSubmitOnEnter.astro +32 -0
- package/src/index.d.ts +43 -0
- package/src/index.js +60 -0
- package/src/lib/canvas.ts +124 -0
- package/src/lib/confetti.ts +127 -0
- package/src/lib/contrast.ts +116 -0
- package/src/lib/form.ts +231 -0
- package/src/lib/geo.ts +77 -0
- package/src/lib/gsap.ts +58 -0
- package/src/lib/land.ts +11 -0
- package/src/lib/lenis.ts +112 -0
- package/src/lib/meta.ts +79 -0
- package/src/lib/morph.ts +74 -0
- package/src/lib/reduced-motion-plugin.js +299 -0
- package/src/lib/runtime.ts +215 -0
- package/src/lib/support.ts +102 -0
- package/src/lib/theme.ts +18 -0
- package/src/lib/toast.ts +17 -0
- package/src/styles/base.css +218 -0
- package/src/styles/motion.css +43 -0
- package/src/styles/theme.css +397 -0
- package/src/styles/theme.tailwind.css +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 azriPtr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @moonarc/core
|
|
2
|
+
|
|
3
|
+
Zero-runtime, `ClientRouter`-safe animation and motion components for Astro:
|
|
4
|
+
scroll reveals, text effects, marquees, backgrounds and UI transitions. Every
|
|
5
|
+
component states its JavaScript cost, measured from a real build; most ship
|
|
6
|
+
none. All honour reduced motion and render readable server HTML.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npx astro add moonarc
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```astro
|
|
13
|
+
---
|
|
14
|
+
import Reveal from '@moonarc/core/Reveal';
|
|
15
|
+
---
|
|
16
|
+
<Reveal><h2>Appears once, stays — after every navigation.</h2></Reveal>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
102 primitives, 67 of them load no JavaScript. By category:
|
|
20
|
+
|
|
21
|
+
- **Text:** SplitText, Typewriter, RotatingText, ShinyText, GradientText, CountUp, TextScramble, WeightWave, SplitFlap, TextRoll, CircularText, GlitchText, StrokeDraw, HighlightMarker, UnderlineHover, BubbleText
|
|
22
|
+
- **Data:** NumberFlow, PriceSwitch, CountdownFlip, Sparkline, BarGrow
|
|
23
|
+
- **Scroll:** Reveal, Parallax, ScrollProgress, CardStack, HorizontalScroll, ScrollScrub, StickyReveal, ScrollExpand, TracingBeam, FooterReveal, ReadingToc
|
|
24
|
+
- **Pointer:** GlyphField, CursorGrid, Tilt, Magnetic, Spotlight, Cursor, ImageTrail, Confetti, HoverImageLinks
|
|
25
|
+
- **Backgrounds:** Aurora, BorderBeam, GridPattern, DotPattern, Noise, Ripple, RetroGrid, AnimatedBeam, OrbitingCircles, Orb, ProgressiveBlur, DottedMap, Particles, Meteors, Globe
|
|
26
|
+
- **Ticker:** Marquee
|
|
27
|
+
- **UI:** Accordion, Dialog (+ morph), Popover, Tabs (+ direction), Carousel, Drawer, Toast, ShimmerButton, StatefulButton, ArrowButton, CopyButton, ThemeToggle (+ ThemeScript), AnimatedIcons, BrowserFrame, CodeTabs, PillNav, Dock, StaggerMenu, CommandPalette, StickyBanner, LinkPreview, Lightbox, ImageCompare, HoverVideo, VideoDialog, AnimatedList, FilterGrid, FileTree, Switch, CheckDraw, OtpInput, AnimatedSelect, PromptInput (+ submitOnEnter), VanishInput, AvatarStack, DynamicIsland, PhoneFrame, LiquidGlass
|
|
28
|
+
- **Loading:** Skeleton, Spinner, Progress, CounterPreloader (+ once)
|
|
29
|
+
- **Page transitions:** PageTransition, Curtain, PersistPlayer
|
|
30
|
+
|
|
31
|
+
Motion theme: `<html data-ma-preset="snap|ui|gentle|lively|ambient">` retunes
|
|
32
|
+
every component; no component hard-codes a curve. Browser support is stated
|
|
33
|
+
per component (`@moonarc/core/support`).
|
|
34
|
+
|
|
35
|
+
Runtime for your own scripts: `@moonarc/core/runtime`. Toasts:
|
|
36
|
+
`@moonarc/core/toast`. GSAP and Lenis adapters:
|
|
37
|
+
`@moonarc/core/gsap`, `@moonarc/core/lenis`.
|
|
38
|
+
|
|
39
|
+
Docs, live demos and measured costs: https://moonarc.dev
|
package/package.json
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moonarc/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Zero-runtime, ClientRouter-safe animation and motion components for Astro: scroll reveals, text effects, marquees, backgrounds and UI transitions. Every component states its measured JS cost.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "azriPtr",
|
|
8
|
+
"homepage": "https://moonarc.dev",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"astro",
|
|
11
|
+
"astro-component",
|
|
12
|
+
"astro-integration",
|
|
13
|
+
"withastro",
|
|
14
|
+
"animation",
|
|
15
|
+
"animations",
|
|
16
|
+
"motion",
|
|
17
|
+
"components",
|
|
18
|
+
"ui",
|
|
19
|
+
"css",
|
|
20
|
+
"scroll-animation",
|
|
21
|
+
"scroll-reveal",
|
|
22
|
+
"text-animation",
|
|
23
|
+
"view-transitions",
|
|
24
|
+
"zero-js"
|
|
25
|
+
],
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./src/index.d.ts",
|
|
34
|
+
"import": "./src/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./Accordion": "./src/components/Accordion.astro",
|
|
37
|
+
"./Aurora": "./src/components/Aurora.astro",
|
|
38
|
+
"./BorderBeam": "./src/components/BorderBeam.astro",
|
|
39
|
+
"./CardStack": "./src/components/CardStack.astro",
|
|
40
|
+
"./Carousel": "./src/components/Carousel.astro",
|
|
41
|
+
"./CountUp": "./src/components/CountUp.astro",
|
|
42
|
+
"./CursorGrid": "./src/components/CursorGrid.astro",
|
|
43
|
+
"./GlyphField": "./src/components/GlyphField.astro",
|
|
44
|
+
"./Dialog": "./src/components/Dialog.astro",
|
|
45
|
+
"./DotPattern": "./src/components/DotPattern.astro",
|
|
46
|
+
"./Drawer": "./src/components/Drawer.astro",
|
|
47
|
+
"./GradientText": "./src/components/GradientText.astro",
|
|
48
|
+
"./GridPattern": "./src/components/GridPattern.astro",
|
|
49
|
+
"./HorizontalScroll": "./src/components/HorizontalScroll.astro",
|
|
50
|
+
"./Magnetic": "./src/components/Magnetic.astro",
|
|
51
|
+
"./Marquee": "./src/components/Marquee.astro",
|
|
52
|
+
"./Noise": "./src/components/Noise.astro",
|
|
53
|
+
"./PageTransition": "./src/components/PageTransition.astro",
|
|
54
|
+
"./Parallax": "./src/components/Parallax.astro",
|
|
55
|
+
"./Popover": "./src/components/Popover.astro",
|
|
56
|
+
"./Progress": "./src/components/Progress.astro",
|
|
57
|
+
"./Reveal": "./src/components/Reveal.astro",
|
|
58
|
+
"./Ripple": "./src/components/Ripple.astro",
|
|
59
|
+
"./RotatingText": "./src/components/RotatingText.astro",
|
|
60
|
+
"./ScrollProgress": "./src/components/ScrollProgress.astro",
|
|
61
|
+
"./ScrollScrub": "./src/components/ScrollScrub.astro",
|
|
62
|
+
"./ShinyText": "./src/components/ShinyText.astro",
|
|
63
|
+
"./Skeleton": "./src/components/Skeleton.astro",
|
|
64
|
+
"./Spinner": "./src/components/Spinner.astro",
|
|
65
|
+
"./SplitText": "./src/components/SplitText.astro",
|
|
66
|
+
"./Spotlight": "./src/components/Spotlight.astro",
|
|
67
|
+
"./Tabs": "./src/components/Tabs.astro",
|
|
68
|
+
"./TextScramble": "./src/components/TextScramble.astro",
|
|
69
|
+
"./Tilt": "./src/components/Tilt.astro",
|
|
70
|
+
"./Toast": "./src/components/Toast.astro",
|
|
71
|
+
"./Typewriter": "./src/components/Typewriter.astro",
|
|
72
|
+
"./WeightWave": "./src/components/WeightWave.astro",
|
|
73
|
+
"./BarGrow": "./src/components/BarGrow.astro",
|
|
74
|
+
"./BubbleText": "./src/components/BubbleText.astro",
|
|
75
|
+
"./CircularText": "./src/components/CircularText.astro",
|
|
76
|
+
"./CountdownFlip": "./src/components/CountdownFlip.astro",
|
|
77
|
+
"./Curtain": "./src/components/Curtain.astro",
|
|
78
|
+
"./GlitchText": "./src/components/GlitchText.astro",
|
|
79
|
+
"./HighlightMarker": "./src/components/HighlightMarker.astro",
|
|
80
|
+
"./NumberFlow": "./src/components/NumberFlow.astro",
|
|
81
|
+
"./PersistPlayer": "./src/components/PersistPlayer.astro",
|
|
82
|
+
"./PriceSwitch": "./src/components/PriceSwitch.astro",
|
|
83
|
+
"./Sparkline": "./src/components/Sparkline.astro",
|
|
84
|
+
"./SplitFlap": "./src/components/SplitFlap.astro",
|
|
85
|
+
"./StrokeDraw": "./src/components/StrokeDraw.astro",
|
|
86
|
+
"./TextRoll": "./src/components/TextRoll.astro",
|
|
87
|
+
"./UnderlineHover": "./src/components/UnderlineHover.astro",
|
|
88
|
+
"./ShimmerButton": "./src/components/ShimmerButton.astro",
|
|
89
|
+
"./StatefulButton": "./src/components/StatefulButton.astro",
|
|
90
|
+
"./ArrowButton": "./src/components/ArrowButton.astro",
|
|
91
|
+
"./CopyButton": "./src/components/CopyButton.astro",
|
|
92
|
+
"./ThemeToggle": "./src/components/ThemeToggle.astro",
|
|
93
|
+
"./ThemeScript": "./src/components/ThemeScript.astro",
|
|
94
|
+
"./AnimatedIcons": "./src/components/AnimatedIcons.astro",
|
|
95
|
+
"./BrowserFrame": "./src/components/BrowserFrame.astro",
|
|
96
|
+
"./CodeTabs": "./src/components/CodeTabs.astro",
|
|
97
|
+
"./StickyReveal": "./src/components/StickyReveal.astro",
|
|
98
|
+
"./ScrollExpand": "./src/components/ScrollExpand.astro",
|
|
99
|
+
"./TracingBeam": "./src/components/TracingBeam.astro",
|
|
100
|
+
"./FooterReveal": "./src/components/FooterReveal.astro",
|
|
101
|
+
"./ReadingToc": "./src/components/ReadingToc.astro",
|
|
102
|
+
"./Cursor": "./src/components/Cursor.astro",
|
|
103
|
+
"./ImageTrail": "./src/components/ImageTrail.astro",
|
|
104
|
+
"./Confetti": "./src/components/Confetti.astro",
|
|
105
|
+
"./RetroGrid": "./src/components/RetroGrid.astro",
|
|
106
|
+
"./AnimatedBeam": "./src/components/AnimatedBeam.astro",
|
|
107
|
+
"./OrbitingCircles": "./src/components/OrbitingCircles.astro",
|
|
108
|
+
"./Orb": "./src/components/Orb.astro",
|
|
109
|
+
"./ProgressiveBlur": "./src/components/ProgressiveBlur.astro",
|
|
110
|
+
"./DottedMap": "./src/components/DottedMap.astro",
|
|
111
|
+
"./Particles": "./src/components/Particles.astro",
|
|
112
|
+
"./Meteors": "./src/components/Meteors.astro",
|
|
113
|
+
"./Globe": "./src/components/Globe.astro",
|
|
114
|
+
"./PillNav": "./src/components/PillNav.astro",
|
|
115
|
+
"./Dock": "./src/components/Dock.astro",
|
|
116
|
+
"./StaggerMenu": "./src/components/StaggerMenu.astro",
|
|
117
|
+
"./CommandPalette": "./src/components/CommandPalette.astro",
|
|
118
|
+
"./StickyBanner": "./src/components/StickyBanner.astro",
|
|
119
|
+
"./LinkPreview": "./src/components/LinkPreview.astro",
|
|
120
|
+
"./Lightbox": "./src/components/Lightbox.astro",
|
|
121
|
+
"./ImageCompare": "./src/components/ImageCompare.astro",
|
|
122
|
+
"./HoverVideo": "./src/components/HoverVideo.astro",
|
|
123
|
+
"./VideoDialog": "./src/components/VideoDialog.astro",
|
|
124
|
+
"./AnimatedList": "./src/components/AnimatedList.astro",
|
|
125
|
+
"./FilterGrid": "./src/components/FilterGrid.astro",
|
|
126
|
+
"./FileTree": "./src/components/FileTree.astro",
|
|
127
|
+
"./HoverImageLinks": "./src/components/HoverImageLinks.astro",
|
|
128
|
+
"./Switch": "./src/components/Switch.astro",
|
|
129
|
+
"./CheckDraw": "./src/components/CheckDraw.astro",
|
|
130
|
+
"./OtpInput": "./src/components/OtpInput.astro",
|
|
131
|
+
"./AnimatedSelect": "./src/components/AnimatedSelect.astro",
|
|
132
|
+
"./PromptInput": "./src/components/PromptInput.astro",
|
|
133
|
+
"./VanishInput": "./src/components/VanishInput.astro",
|
|
134
|
+
"./AvatarStack": "./src/components/AvatarStack.astro",
|
|
135
|
+
"./CounterPreloader": "./src/components/CounterPreloader.astro",
|
|
136
|
+
"./DynamicIsland": "./src/components/DynamicIsland.astro",
|
|
137
|
+
"./PhoneFrame": "./src/components/PhoneFrame.astro",
|
|
138
|
+
"./LiquidGlass": "./src/components/LiquidGlass.astro",
|
|
139
|
+
"./internal/Probe": "./src/components/Probe.astro",
|
|
140
|
+
"./runtime": {
|
|
141
|
+
"types": "./src/lib/runtime.ts",
|
|
142
|
+
"import": "./src/lib/runtime.ts"
|
|
143
|
+
},
|
|
144
|
+
"./meta": {
|
|
145
|
+
"types": "./src/lib/meta.ts",
|
|
146
|
+
"import": "./src/lib/meta.ts"
|
|
147
|
+
},
|
|
148
|
+
"./gsap": {
|
|
149
|
+
"types": "./src/lib/gsap.ts",
|
|
150
|
+
"import": "./src/lib/gsap.ts"
|
|
151
|
+
},
|
|
152
|
+
"./lenis": {
|
|
153
|
+
"types": "./src/lib/lenis.ts",
|
|
154
|
+
"import": "./src/lib/lenis.ts"
|
|
155
|
+
},
|
|
156
|
+
"./support": {
|
|
157
|
+
"types": "./src/lib/support.ts",
|
|
158
|
+
"import": "./src/lib/support.ts"
|
|
159
|
+
},
|
|
160
|
+
"./theme": {
|
|
161
|
+
"types": "./src/lib/theme.ts",
|
|
162
|
+
"import": "./src/lib/theme.ts"
|
|
163
|
+
},
|
|
164
|
+
"./toast": {
|
|
165
|
+
"types": "./src/lib/toast.ts",
|
|
166
|
+
"import": "./src/lib/toast.ts"
|
|
167
|
+
},
|
|
168
|
+
"./canvas": {
|
|
169
|
+
"types": "./src/lib/canvas.ts",
|
|
170
|
+
"import": "./src/lib/canvas.ts"
|
|
171
|
+
},
|
|
172
|
+
"./confetti": {
|
|
173
|
+
"types": "./src/lib/confetti.ts",
|
|
174
|
+
"import": "./src/lib/confetti.ts"
|
|
175
|
+
},
|
|
176
|
+
"./geo": {
|
|
177
|
+
"types": "./src/lib/geo.ts",
|
|
178
|
+
"import": "./src/lib/geo.ts"
|
|
179
|
+
},
|
|
180
|
+
"./land": {
|
|
181
|
+
"types": "./src/lib/land.ts",
|
|
182
|
+
"import": "./src/lib/land.ts"
|
|
183
|
+
},
|
|
184
|
+
"./morph": {
|
|
185
|
+
"types": "./src/lib/morph.ts",
|
|
186
|
+
"import": "./src/lib/morph.ts"
|
|
187
|
+
},
|
|
188
|
+
"./contrast": {
|
|
189
|
+
"types": "./src/lib/contrast.ts",
|
|
190
|
+
"import": "./src/lib/contrast.ts"
|
|
191
|
+
},
|
|
192
|
+
"./form": {
|
|
193
|
+
"types": "./src/lib/form.ts",
|
|
194
|
+
"import": "./src/lib/form.ts"
|
|
195
|
+
},
|
|
196
|
+
"./styles": "./src/styles/motion.css",
|
|
197
|
+
"./styles/base.css": "./src/styles/base.css",
|
|
198
|
+
"./styles/motion.css": "./src/styles/motion.css",
|
|
199
|
+
"./theme.css": "./src/styles/theme.css",
|
|
200
|
+
"./styles/theme.css": "./src/styles/theme.css",
|
|
201
|
+
"./styles/theme.tailwind.css": "./src/styles/theme.tailwind.css",
|
|
202
|
+
"./package.json": "./package.json"
|
|
203
|
+
},
|
|
204
|
+
"peerDependencies": {
|
|
205
|
+
"astro": ">=5",
|
|
206
|
+
"gsap": ">=3.12",
|
|
207
|
+
"lenis": ">=1.1"
|
|
208
|
+
},
|
|
209
|
+
"devDependencies": {
|
|
210
|
+
"@astrojs/check": "^0.9.10",
|
|
211
|
+
"astro": "^7.3.2",
|
|
212
|
+
"typescript": "^5.9.3"
|
|
213
|
+
},
|
|
214
|
+
"publishConfig": {
|
|
215
|
+
"access": "public"
|
|
216
|
+
},
|
|
217
|
+
"peerDependenciesMeta": {
|
|
218
|
+
"gsap": {
|
|
219
|
+
"optional": true
|
|
220
|
+
},
|
|
221
|
+
"lenis": {
|
|
222
|
+
"optional": true
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
"scripts": {
|
|
226
|
+
"check": "astro check --minimumSeverity error"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Accordion — native <details> with an animated height, zero JS.
|
|
4
|
+
*
|
|
5
|
+
* The browser owns open/close, keyboard, and (with `exclusive`) the one-open
|
|
6
|
+
* rule via the name attribute. The animation is ::details-content laid out
|
|
7
|
+
* as a grid whose row goes 0fr → 1fr, so the body's height interpolates from
|
|
8
|
+
* nothing to auto without measuring anything. Browsers without
|
|
9
|
+
* ::details-content open instantly — a fallback, not a failure.
|
|
10
|
+
*/
|
|
11
|
+
import type { HTMLAttributes } from 'astro/types';
|
|
12
|
+
|
|
13
|
+
interface Item {
|
|
14
|
+
title: string;
|
|
15
|
+
/** HTML string. */
|
|
16
|
+
body: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Props extends HTMLAttributes<'div'> {
|
|
20
|
+
items: Item[];
|
|
21
|
+
/** Only one item open at a time (details name=). */
|
|
22
|
+
exclusive?: boolean;
|
|
23
|
+
/** Index of the item open on load. */
|
|
24
|
+
open?: number;
|
|
25
|
+
/** Group name when exclusive; defaults to a generated one. */
|
|
26
|
+
name?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { items, exclusive = false, open, name = `ma-acc-${Math.random().toString(36).slice(2, 7)}`, class: className, ...rest } = Astro.props;
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
<div class:list={['ma-accordion', className]} {...rest}>
|
|
33
|
+
{
|
|
34
|
+
items.map((item, i) => (
|
|
35
|
+
<details class="ma-accordion__item" name={exclusive ? name : undefined} open={open === i}>
|
|
36
|
+
<summary class="ma-accordion__summary">
|
|
37
|
+
<span>{item.title}</span>
|
|
38
|
+
<svg class="ma-accordion__chevron" aria-hidden="true" viewBox="0 0 16 16" width="16" height="16"><path d="M4 6l4 4 4-4" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
|
39
|
+
</summary>
|
|
40
|
+
<div class="ma-accordion__body" set:html={item.body} />
|
|
41
|
+
</details>
|
|
42
|
+
))
|
|
43
|
+
}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<style is:global>
|
|
47
|
+
@layer components {
|
|
48
|
+
:where(.ma-accordion__item) {
|
|
49
|
+
border-top: 1px solid var(--ma-edge);
|
|
50
|
+
}
|
|
51
|
+
:where(.ma-accordion__item:last-child) {
|
|
52
|
+
border-bottom: 1px solid var(--ma-edge);
|
|
53
|
+
}
|
|
54
|
+
:where(.ma-accordion__summary) {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
gap: 1rem;
|
|
59
|
+
padding: 0.875rem 0;
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
list-style: none;
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
}
|
|
64
|
+
:where(.ma-accordion__summary)::-webkit-details-marker {
|
|
65
|
+
display: none;
|
|
66
|
+
}
|
|
67
|
+
:where(.ma-accordion__chevron) {
|
|
68
|
+
flex: none;
|
|
69
|
+
opacity: 0.6;
|
|
70
|
+
transition: rotate var(--ma-duration) var(--ma-ease);
|
|
71
|
+
}
|
|
72
|
+
:where(.ma-accordion__item[open] .ma-accordion__chevron) {
|
|
73
|
+
rotate: 180deg;
|
|
74
|
+
}
|
|
75
|
+
/* the animated part: the content box is a grid whose only row interpolates 0fr → 1fr */
|
|
76
|
+
:where(.ma-accordion__item)::details-content {
|
|
77
|
+
display: grid;
|
|
78
|
+
grid-template-rows: 0fr;
|
|
79
|
+
transition:
|
|
80
|
+
grid-template-rows var(--ma-duration) var(--ma-ease),
|
|
81
|
+
content-visibility var(--ma-duration) allow-discrete;
|
|
82
|
+
}
|
|
83
|
+
:where(.ma-accordion__item[open])::details-content {
|
|
84
|
+
grid-template-rows: 1fr;
|
|
85
|
+
}
|
|
86
|
+
:where(.ma-accordion__body) {
|
|
87
|
+
min-height: 0;
|
|
88
|
+
overflow: clip;
|
|
89
|
+
padding-bottom: 0;
|
|
90
|
+
transition: padding-bottom var(--ma-duration) var(--ma-ease);
|
|
91
|
+
}
|
|
92
|
+
:where(.ma-accordion__item[open] .ma-accordion__body) {
|
|
93
|
+
padding-bottom: 1rem;
|
|
94
|
+
}
|
|
95
|
+
/* ::details-content in a rule of its own: in an engine that does not know it, a selector list that names it is
|
|
96
|
+
dropped whole, and the body and the chevron kept their transitions under reduced motion. The minifier merges
|
|
97
|
+
neighbouring rules with the same declarations back into one list, so this one sits behind a feature test */
|
|
98
|
+
@media (prefers-reduced-motion: reduce) {
|
|
99
|
+
@supports selector(::details-content) {
|
|
100
|
+
:where(.ma-accordion__item)::details-content {
|
|
101
|
+
transition: none;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
:where(.ma-accordion__body),
|
|
105
|
+
:where(.ma-accordion__chevron) {
|
|
106
|
+
transition: none;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ComponentMeta } from '../lib/meta';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
name: 'Accordion',
|
|
5
|
+
slug: 'accordion',
|
|
6
|
+
title: 'Accordion',
|
|
7
|
+
description: 'Native <details> items whose height animates open and closed, with an optional one-at-a-time rule the browser enforces. Zero JavaScript: ::details-content is a grid whose row interpolates from 0fr to 1fr, so height-to-auto costs nothing to measure.',
|
|
8
|
+
summary: 'An accordion on native <details> whose height animates open and closed, optionally one item at a time.',
|
|
9
|
+
category: 'ui',
|
|
10
|
+
tier: 'A',
|
|
11
|
+
trigger: ['click'],
|
|
12
|
+
support: { baseline: 'newly', needs: ['details-content', 'allow-discrete', 'details-name'], fallback: 'items open and close instantly' },
|
|
13
|
+
readout: '<Accordion exclusive>',
|
|
14
|
+
usage: `<Accordion\n exclusive\n open={0}\n items={[\n { title: 'Is it really zero JS?', body: '<p>For this one, yes. The browser animates it.</p>' },\n { title: 'Keyboard?', body: '<p>Native: Tab, Enter, Space.</p>' },\n ]}\n/>`,
|
|
15
|
+
props: [
|
|
16
|
+
{ name: 'items', type: '{ title: string; body: string }[]', description: 'Items; body is an HTML string.' },
|
|
17
|
+
{ name: 'exclusive', type: 'boolean', default: 'false', description: 'Only one open at a time, via the details name attribute.' },
|
|
18
|
+
{ name: 'open', type: 'number', description: 'Index of the item open on load.' },
|
|
19
|
+
{ name: 'name', type: 'string', default: 'generated', description: 'Group name used when exclusive.' },
|
|
20
|
+
],
|
|
21
|
+
reducedMotion: 'Opens and closes instantly; the chevron still turns.',
|
|
22
|
+
clientRouter: 'CSS-only; native elements keep their state per page.',
|
|
23
|
+
craft: [
|
|
24
|
+
'grid-template-rows 0fr → 1fr is the one way to animate to auto height without JavaScript or interpolate-size; the body needs min-height: 0 and overflow: clip.',
|
|
25
|
+
'content-visibility transitions with allow-discrete so the closing body stays visible until the row has collapsed.',
|
|
26
|
+
'The chevron rotates on the same curve and duration as the height, so the two read as one motion.',
|
|
27
|
+
'No custom marker element: the default disclosure triangle is hidden and the chevron is inside the summary, where the click target already is.',
|
|
28
|
+
],
|
|
29
|
+
related: ['tabs', 'dialog', 'popover'],
|
|
30
|
+
intents: ['accordion', 'faq accordion', 'animate details summary', 'collapsible sections', 'height auto transition'],
|
|
31
|
+
replaces: ['Accordion (Radix / shadcn)', 'Accordion (Aceternity)', 'FAQ blocks'],
|
|
32
|
+
fixture: { props: { items: [{ title: 'Fixture content for Accordion', body: '<p>Body</p>' }, { title: 'Second', body: '<p>Body two</p>' }] }, expect: 'Fixture content for Accordion' },
|
|
33
|
+
} satisfies ComponentMeta;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* AnimatedBeam — packets of light travel along curves between nodes. The
|
|
4
|
+
* layout is a preset (hub: satellites around a centre · row: a chain ·
|
|
5
|
+
* fan: many into one); the server computes every node position and every
|
|
6
|
+
* path in percent of the box, so the SVG and the slotted nodes share the
|
|
7
|
+
* same coordinates and nothing is measured in the DOM. Each beam is one
|
|
8
|
+
* dash whose offset runs from before the start to past the end (a comet
|
|
9
|
+
* tail is a longer, fainter dash behind it). The stroke keeps its width in
|
|
10
|
+
* px while the drawing stretches, which puts dashes in screen px too, so a
|
|
11
|
+
* path's on-screen length is CSS: eight chords from the server, each a
|
|
12
|
+
* hypot() of cqw and cqh. The delay per path is its index over the count
|
|
13
|
+
* of the period, so the packets are spread evenly. Zero script; responsive
|
|
14
|
+
* because everything is a percentage.
|
|
15
|
+
*/
|
|
16
|
+
import type { HTMLAttributes } from 'astro/types';
|
|
17
|
+
|
|
18
|
+
interface Props extends HTMLAttributes<'div'> {
|
|
19
|
+
/** hub: one centre (slot `hub`) with `nodes` satellites · row: `nodes` nodes in a line, left to right · fan: `nodes` on the left flowing into one on the right (slot `hub`). */
|
|
20
|
+
layout?: 'hub' | 'row' | 'fan';
|
|
21
|
+
/** Satellite / step count, 2–8. */
|
|
22
|
+
nodes?: number;
|
|
23
|
+
/** Seconds a packet takes to travel one path. */
|
|
24
|
+
duration?: number;
|
|
25
|
+
/** Packet colour. */
|
|
26
|
+
color?: string;
|
|
27
|
+
/** Line colour behind the packets. */
|
|
28
|
+
track?: string;
|
|
29
|
+
/** Bend of the curves, 0 straight … 1 deeply curved. */
|
|
30
|
+
curve?: number;
|
|
31
|
+
/** Packet length as a fraction of the path. */
|
|
32
|
+
length?: number;
|
|
33
|
+
/** Packets flow away from the hub instead of toward it (row: right to left). */
|
|
34
|
+
reverse?: boolean;
|
|
35
|
+
/** Line width in px. */
|
|
36
|
+
width?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { layout = 'hub', nodes = 5, duration = 3, color = 'currentColor', track = 'var(--ma-edge)', curve = 0.35, length = 0.18, reverse = false, width = 1.5, class: className, style, ...rest } = Astro.props;
|
|
40
|
+
const n = Math.max(2, Math.min(8, Math.round(nodes)));
|
|
41
|
+
type Pt = [number, number];
|
|
42
|
+
const r1 = (v: number) => Math.round(v * 10) / 10;
|
|
43
|
+
|
|
44
|
+
// node positions in percent; every path runs satellite → hub (or left → right)
|
|
45
|
+
let hub: Pt | null = null;
|
|
46
|
+
let sats: Pt[] = [];
|
|
47
|
+
let links: [Pt, Pt][] = [];
|
|
48
|
+
if (layout === 'hub') {
|
|
49
|
+
hub = [50, 50];
|
|
50
|
+
sats = Array.from({ length: n }, (_, i) => {
|
|
51
|
+
const a = -Math.PI / 2 + (i * 2 * Math.PI) / n;
|
|
52
|
+
return [r1(50 + Math.cos(a) * 38), r1(50 + Math.sin(a) * 36)];
|
|
53
|
+
});
|
|
54
|
+
links = sats.map((s) => [s, hub!]);
|
|
55
|
+
} else if (layout === 'fan') {
|
|
56
|
+
hub = [82, 50];
|
|
57
|
+
sats = Array.from({ length: n }, (_, i) => [18, r1(n === 1 ? 50 : 12 + (i * 76) / (n - 1))]);
|
|
58
|
+
links = sats.map((s) => [s, hub!]);
|
|
59
|
+
} else {
|
|
60
|
+
sats = Array.from({ length: n }, (_, i) => [r1(10 + (i * 80) / (n - 1)), 50]);
|
|
61
|
+
links = sats.slice(1).map((s, i) => [sats[i]!, s]);
|
|
62
|
+
}
|
|
63
|
+
// quadratic curve with the control point pushed off the chord, alternating sides so a hub reads as a flower, a row as a wave
|
|
64
|
+
const r2 = (v: number) => Math.round(v * 100) / 100;
|
|
65
|
+
const paths = links.map(([a, b], i) => {
|
|
66
|
+
const mx = (a[0] + b[0]) / 2;
|
|
67
|
+
const my = (a[1] + b[1]) / 2;
|
|
68
|
+
const dx = b[0] - a[0];
|
|
69
|
+
const dy = b[1] - a[1];
|
|
70
|
+
const side = i % 2 ? -1 : 1;
|
|
71
|
+
const cx = r1(mx - dy * curve * side);
|
|
72
|
+
const cy = r1(my + dx * curve * side);
|
|
73
|
+
// the on-screen length: one user unit is 1cqw across and 1cqh down (the viewBox is stretched to the box), so eight
|
|
74
|
+
// chords of the curve summed as hypot() in those units follow the box at any size, within half a percent of the arc
|
|
75
|
+
const at = (t: number): Pt => [(1 - t) ** 2 * a[0] + 2 * (1 - t) * t * cx + t * t * b[0], (1 - t) ** 2 * a[1] + 2 * (1 - t) * t * cy + t * t * b[1]];
|
|
76
|
+
const chords = Array.from({ length: 8 }, (_, k) => {
|
|
77
|
+
const [x0, y0] = at(k / 8);
|
|
78
|
+
const [x1, y1] = at((k + 1) / 8);
|
|
79
|
+
return `hypot(${r2(x1 - x0)}cqw,${r2(y1 - y0)}cqh)`;
|
|
80
|
+
});
|
|
81
|
+
return { d: reverse ? `M${b[0]} ${b[1]}Q${cx} ${cy} ${a[0]} ${a[1]}` : `M${a[0]} ${a[1]}Q${cx} ${cy} ${b[0]} ${b[1]}`, len: `calc(${chords.join(' + ')})` };
|
|
82
|
+
});
|
|
83
|
+
const inline = [`--ma-beams-dur:${duration}s`, `--ma-beams-color:${color}`, `--ma-beams-track:${track}`, `--ma-beams-len:${length}`, `--ma-beams-n:${paths.length}`, `--ma-beams-w:${width}px`, typeof style === 'string' ? style : ''].filter(Boolean).join(';');
|
|
84
|
+
const slotNames = Array.from({ length: n }, (_, i) => `node-${i + 1}` as const);
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
<div class:list={['ma-beams', className]} data-ma-beams data-layout={layout} style={inline} {...rest}>
|
|
88
|
+
<div class="ma-beams__lines">
|
|
89
|
+
<svg class="ma-beams__svg" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
|
|
90
|
+
{paths.map((p, i) => (
|
|
91
|
+
<g style={`--ma-beams-i:${i};--ma-beams-l:${p.len}`}>
|
|
92
|
+
<path class="ma-beams__track" d={p.d} />
|
|
93
|
+
<path class="ma-beams__tail" d={p.d} />
|
|
94
|
+
<path class="ma-beams__packet" d={p.d} />
|
|
95
|
+
</g>
|
|
96
|
+
))}
|
|
97
|
+
</svg>
|
|
98
|
+
</div>
|
|
99
|
+
{hub && (
|
|
100
|
+
<div class="ma-beams__node ma-beams__node--hub" style={`--ma-beams-x:${hub[0]}%;--ma-beams-y:${hub[1]}%`}>
|
|
101
|
+
<slot name="hub"><span class="ma-beams__dot"></span></slot>
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
{sats.map((p, i) => (
|
|
105
|
+
<div class="ma-beams__node" style={`--ma-beams-x:${p[0]}%;--ma-beams-y:${p[1]}%`}>
|
|
106
|
+
{i === 0 && <slot name="node-1"><span class="ma-beams__dot"></span></slot>}
|
|
107
|
+
{i === 1 && <slot name="node-2"><span class="ma-beams__dot"></span></slot>}
|
|
108
|
+
{i === 2 && <slot name="node-3"><span class="ma-beams__dot"></span></slot>}
|
|
109
|
+
{i === 3 && <slot name="node-4"><span class="ma-beams__dot"></span></slot>}
|
|
110
|
+
{i === 4 && <slot name="node-5"><span class="ma-beams__dot"></span></slot>}
|
|
111
|
+
{i === 5 && <slot name="node-6"><span class="ma-beams__dot"></span></slot>}
|
|
112
|
+
{i === 6 && <slot name="node-7"><span class="ma-beams__dot"></span></slot>}
|
|
113
|
+
{i === 7 && <slot name="node-8"><span class="ma-beams__dot"></span></slot>}
|
|
114
|
+
</div>
|
|
115
|
+
))}
|
|
116
|
+
{slotNames.length === 0 && <slot />}
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<style is:global>
|
|
120
|
+
@layer components {
|
|
121
|
+
:where(.ma-beams) {
|
|
122
|
+
position: relative;
|
|
123
|
+
width: 100%;
|
|
124
|
+
height: 100%;
|
|
125
|
+
}
|
|
126
|
+
/* the paths' lengths are in cqw / cqh of the drawing's own box, the component's size with no padding. It holds no
|
|
127
|
+
slotted node, so a container query or a cq unit inside a node still resolves against the container it had */
|
|
128
|
+
:where(.ma-beams__lines) {
|
|
129
|
+
position: absolute;
|
|
130
|
+
inset: 0;
|
|
131
|
+
container-type: size;
|
|
132
|
+
}
|
|
133
|
+
:where(.ma-beams__svg) {
|
|
134
|
+
position: absolute;
|
|
135
|
+
inset: 0;
|
|
136
|
+
width: 100%;
|
|
137
|
+
height: 100%;
|
|
138
|
+
overflow: visible;
|
|
139
|
+
}
|
|
140
|
+
:where(.ma-beams__svg path) {
|
|
141
|
+
fill: none;
|
|
142
|
+
stroke-width: var(--ma-beams-w, 1.5px);
|
|
143
|
+
stroke-linecap: round;
|
|
144
|
+
/* the viewBox is stretched to the box; the stroke keeps its width in px, and its dashes are in screen px with it */
|
|
145
|
+
vector-effect: non-scaling-stroke;
|
|
146
|
+
}
|
|
147
|
+
:where(.ma-beams__track) {
|
|
148
|
+
stroke: var(--ma-beams-track, var(--ma-edge));
|
|
149
|
+
}
|
|
150
|
+
/* the packet: a dash `len` of the path's on-screen length --ma-beams-l, a gap of twice that so only one packet is on
|
|
151
|
+
the path; the offset runs from `len` × l (the dash still before the start) to −l (past the end). pathLength="1" cannot
|
|
152
|
+
do this: under non-scaling-stroke the engines lay its units along the screen-space path, so a stretched box drew a
|
|
153
|
+
row of short dashes. */
|
|
154
|
+
:where(.ma-beams__packet),
|
|
155
|
+
:where(.ma-beams__tail) {
|
|
156
|
+
stroke: var(--ma-beams-color, currentColor);
|
|
157
|
+
stroke-dasharray: calc(var(--ma-beams-len, 0.18) * var(--ma-beams-l)) calc(var(--ma-beams-l) * 2);
|
|
158
|
+
animation: ma-beams var(--ma-beams-dur) linear infinite;
|
|
159
|
+
animation-delay: calc(var(--ma-beams-i, 0) * var(--ma-beams-dur) / var(--ma-beams-n, 1) * -1);
|
|
160
|
+
}
|
|
161
|
+
/* the tail: three times the packet, a quarter as bright, ending where the packet ends */
|
|
162
|
+
:where(.ma-beams__tail) {
|
|
163
|
+
stroke-dasharray: calc(var(--ma-beams-len, 0.18) * 3 * var(--ma-beams-l)) calc(var(--ma-beams-l) * 2);
|
|
164
|
+
opacity: 0.25;
|
|
165
|
+
animation-name: ma-beams-tail;
|
|
166
|
+
}
|
|
167
|
+
:where(.ma-beams__node) {
|
|
168
|
+
position: absolute;
|
|
169
|
+
left: var(--ma-beams-x, 50%);
|
|
170
|
+
top: var(--ma-beams-y, 50%);
|
|
171
|
+
translate: -50% -50%;
|
|
172
|
+
display: grid;
|
|
173
|
+
place-items: center;
|
|
174
|
+
}
|
|
175
|
+
:where(.ma-beams__dot) {
|
|
176
|
+
display: block;
|
|
177
|
+
width: 0.75rem;
|
|
178
|
+
height: 0.75rem;
|
|
179
|
+
border-radius: 50%;
|
|
180
|
+
border: 1px solid var(--ma-edge);
|
|
181
|
+
background: var(--ma-panel);
|
|
182
|
+
}
|
|
183
|
+
:where(.ma-beams__node--hub .ma-beams__dot) {
|
|
184
|
+
width: 1.25rem;
|
|
185
|
+
height: 1.25rem;
|
|
186
|
+
background: var(--ma-ink);
|
|
187
|
+
}
|
|
188
|
+
@media (prefers-reduced-motion: reduce) {
|
|
189
|
+
:where(.ma-beams__packet),
|
|
190
|
+
:where(.ma-beams__tail) {
|
|
191
|
+
animation: none;
|
|
192
|
+
stroke-dasharray: none;
|
|
193
|
+
opacity: 0.6;
|
|
194
|
+
}
|
|
195
|
+
:where(.ma-beams__tail) {
|
|
196
|
+
display: none;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@keyframes ma-beams {
|
|
202
|
+
from {
|
|
203
|
+
stroke-dashoffset: calc(var(--ma-beams-len, 0.18) * var(--ma-beams-l));
|
|
204
|
+
}
|
|
205
|
+
to {
|
|
206
|
+
stroke-dashoffset: calc(var(--ma-beams-l) * -1);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
@keyframes ma-beams-tail {
|
|
210
|
+
from {
|
|
211
|
+
stroke-dashoffset: calc(var(--ma-beams-len, 0.18) * 3 * var(--ma-beams-l));
|
|
212
|
+
}
|
|
213
|
+
to {
|
|
214
|
+
stroke-dashoffset: calc(var(--ma-beams-l) * -1 + var(--ma-beams-len, 0.18) * 2 * var(--ma-beams-l));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
</style>
|