@anubis609/astroanimate-core 0.1.2

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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +212 -0
  3. package/dist/components/AnimatedBorderButton/AnimatedBorderButton.astro +129 -0
  4. package/dist/components/AnimatedBorderButton/index.js +3 -0
  5. package/dist/components/AnimatedBorderButton/index.js.map +1 -0
  6. package/dist/components/AnimatedButton/AnimatedButton.astro +299 -0
  7. package/dist/components/AnimatedButton/index.js +3 -0
  8. package/dist/components/AnimatedButton/index.js.map +1 -0
  9. package/dist/components/AnimatedCard/AnimatedCard.astro +832 -0
  10. package/dist/components/AnimatedCard/index.js +3 -0
  11. package/dist/components/AnimatedCard/index.js.map +1 -0
  12. package/dist/components/AnimatedTabs/AnimatedTabs.astro +348 -0
  13. package/dist/components/AnimatedTabs/index.js +3 -0
  14. package/dist/components/AnimatedTabs/index.js.map +1 -0
  15. package/dist/components/ArrowCTAButton/ArrowCTAButton.astro +159 -0
  16. package/dist/components/ArticleCard/ArticleCard.astro +208 -0
  17. package/dist/components/CardStack/CardStack.astro +444 -0
  18. package/dist/components/CardStack/index.js +3 -0
  19. package/dist/components/CardStack/index.js.map +1 -0
  20. package/dist/components/CountUp/CountUp.astro +89 -0
  21. package/dist/components/CountUp/index.js +3 -0
  22. package/dist/components/CountUp/index.js.map +1 -0
  23. package/dist/components/Dock/Dock.astro +567 -0
  24. package/dist/components/Dock/DockItem.astro +135 -0
  25. package/dist/components/Dropdown/Dropdown.astro +264 -0
  26. package/dist/components/ExpandableCard/ExpandableCard.astro +402 -0
  27. package/dist/components/ExpandableCard/index.js +3 -0
  28. package/dist/components/ExpandableCard/index.js.map +1 -0
  29. package/dist/components/FadeInText/FadeInText.astro +314 -0
  30. package/dist/components/FadeInText/index.js +3 -0
  31. package/dist/components/FadeInText/index.js.map +1 -0
  32. package/dist/components/FillHoverButton/FillHoverButton.astro +125 -0
  33. package/dist/components/GitHubShineButton/GitHubShineButton.astro +208 -0
  34. package/dist/components/GlassCard/GlassCard.astro +245 -0
  35. package/dist/components/GlassCard/index.js +3 -0
  36. package/dist/components/GlassCard/index.js.map +1 -0
  37. package/dist/components/GridDotsBackground/GridDotsBackground.astro +144 -0
  38. package/dist/components/HighlightText/HighlightText.astro +106 -0
  39. package/dist/components/InfiniteMarquee/InfiniteMarquee.astro +339 -0
  40. package/dist/components/JobCard/JobCard.astro +230 -0
  41. package/dist/components/LiquidGlassCard/LiquidGlassCard.astro +569 -0
  42. package/dist/components/Loader/Loader.astro +156 -0
  43. package/dist/components/Loader/index.js +3 -0
  44. package/dist/components/Loader/index.js.map +1 -0
  45. package/dist/components/NewsletterPopupCard/NewsletterPopupCard.astro +331 -0
  46. package/dist/components/ProductReviewCard/ProductReviewCard.astro +188 -0
  47. package/dist/components/ProgressBar/ProgressBar.astro +137 -0
  48. package/dist/components/ProgressBar/index.js +3 -0
  49. package/dist/components/ProgressBar/index.js.map +1 -0
  50. package/dist/components/RevealImage/RevealImage.astro +160 -0
  51. package/dist/components/RevealImage/index.js +3 -0
  52. package/dist/components/RevealImage/index.js.map +1 -0
  53. package/dist/components/ScaleIn/ScaleIn.astro +231 -0
  54. package/dist/components/ScaleIn/index.js +3 -0
  55. package/dist/components/ScaleIn/index.js.map +1 -0
  56. package/dist/components/SlidingOverlayButton/SlidingOverlayButton.astro +126 -0
  57. package/dist/components/StaggerTextButton/StaggerTextButton.astro +132 -0
  58. package/dist/components/Tooltip/Tooltip.astro +255 -0
  59. package/dist/components/Tooltip/index.js +3 -0
  60. package/dist/components/Tooltip/index.js.map +1 -0
  61. package/dist/components/TypewriterText/TypewriterText.astro +380 -0
  62. package/dist/components/TypewriterText/index.js +3 -0
  63. package/dist/components/TypewriterText/index.js.map +1 -0
  64. package/dist/components/index.js +33 -0
  65. package/dist/components/index.js.map +1 -0
  66. package/dist/index.js +31 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/internal/countup.js +90 -0
  69. package/dist/internal/countup.js.map +1 -0
  70. package/dist/internal/dropdown.js +166 -0
  71. package/dist/internal/dropdown.js.map +1 -0
  72. package/dist/internal/fadein.js +116 -0
  73. package/dist/internal/fadein.js.map +1 -0
  74. package/dist/internal/guards.js +12 -0
  75. package/dist/internal/guards.js.map +1 -0
  76. package/dist/internal/tabs.js +140 -0
  77. package/dist/internal/tabs.js.map +1 -0
  78. package/package.json +229 -0
@@ -0,0 +1,3 @@
1
+ export { default } from './AnimatedCard.astro';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
@@ -0,0 +1,348 @@
1
+ ---
2
+ /**
3
+ * AnimatedTabs — A CSS-first tab component with JS enhancement for smooth indicator transitions.
4
+ *
5
+ * Satisfies 8-checkpoint standard:
6
+ * 1. Visible Without JS: Initial tab panel is visible by default.
7
+ * 2. Zero Hydration: No framework hydration required.
8
+ * 3. Multiple Instances Safe: Uses unique selectors and WeakMap tracking.
9
+ * 4. Works in Build + Preview: Standard Astro component.
10
+ * 5. No Astro Internals: Uses public slots API.
11
+ * 6. Reduced Motion Respected: CSS and JS guards for prefers-reduced-motion.
12
+ * 7. CSS-First: Layout and state driven by data-attributes.
13
+ * 8. JS Only Enhances: Smooth indicator and keyboard navigation added by JS.
14
+ */
15
+
16
+ interface TabDef {
17
+ id: string;
18
+ label: string;
19
+ }
20
+
21
+ interface Props {
22
+ tabs: TabDef[];
23
+ defaultTab?: string;
24
+ variant?: "pill" | "underline";
25
+ color?: string;
26
+ size?: "sm" | "md" | "lg";
27
+ backgroundColor?: string;
28
+ inactiveTextColor?: string;
29
+ activeTextColor?: string;
30
+ showBorder?: boolean;
31
+ fullWidth?: boolean;
32
+ class?: string;
33
+ [key: string]: unknown;
34
+ }
35
+
36
+ const {
37
+ tabs = [],
38
+ defaultTab,
39
+ variant = "pill",
40
+ color = "#3b82f6",
41
+ backgroundColor = "#f1f5f9",
42
+ inactiveTextColor = "#64748b",
43
+ activeTextColor,
44
+ showBorder = true,
45
+ fullWidth = true,
46
+ size = "md",
47
+ class: className = "",
48
+ ...rest
49
+ } = Astro.props as Props;
50
+
51
+ const safeTabs = Array.isArray(tabs)
52
+ ? tabs.filter((t) => t && t.id && t.label)
53
+ : [];
54
+
55
+ const initialTab =
56
+ defaultTab && safeTabs.some((t) => t.id === defaultTab)
57
+ ? defaultTab
58
+ : safeTabs[0]?.id;
59
+
60
+ const panelHtmlById = new Map<string, string>();
61
+ for (const t of safeTabs) {
62
+ const slotName = `panel:${t.id}`;
63
+ panelHtmlById.set(t.id, await Astro.slots.render(slotName));
64
+ }
65
+ ---
66
+
67
+ <style>
68
+ .astro-animated-tabs {
69
+ width: 100%;
70
+ font-family: system-ui, -apple-system, sans-serif;
71
+ --tab-accent: var(--tabs-color, #3b82f6);
72
+ --tab-bg-inactive: var(--tabs-bg-inactive, #f1f5f9);
73
+ --tab-text-inactive: var(--tabs-text-inactive, #64748b);
74
+ --tab-text-active: var(--tabs-text-active, #ffffff);
75
+ --tab-border: #e2e8f0;
76
+ }
77
+
78
+ .tablist {
79
+ display: flex;
80
+ gap: 0.25rem;
81
+ background: var(--tab-bg-inactive);
82
+ padding: 0.25rem;
83
+ border-radius: 0.5rem;
84
+ position: relative;
85
+ overflow-x: auto;
86
+ scrollbar-width: none;
87
+ }
88
+
89
+ .tablist::-webkit-scrollbar {
90
+ display: none;
91
+ }
92
+
93
+ /* Indicator - Positioned via data attributes set by JS */
94
+ .indicator {
95
+ position: absolute;
96
+ height: calc(100% - 0.5rem);
97
+ top: 0.25rem;
98
+ left: 0;
99
+ background: var(--tab-accent);
100
+ border-radius: 0.375rem;
101
+ width: 0;
102
+ transform: translateX(0);
103
+ transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
104
+ pointer-events: none;
105
+ opacity: 0;
106
+ }
107
+
108
+ /* Show indicator once JS has calculated positions */
109
+ [data-ready="true"] .indicator {
110
+ opacity: 1;
111
+ transform: translateX(calc(var(--indicator-x, 0) * 1px));
112
+ width: calc(var(--indicator-w, 0) * 1px);
113
+ }
114
+
115
+ /* Underline Variant */
116
+ [data-variant="underline"] .tablist {
117
+ background: transparent;
118
+ border-bottom: 2px solid var(--tab-border);
119
+ border-radius: 0;
120
+ padding: 0;
121
+ }
122
+
123
+ [data-variant="underline"] .indicator {
124
+ height: 2px;
125
+ top: auto;
126
+ bottom: -2px;
127
+ left: 0;
128
+ border-radius: 0;
129
+ }
130
+
131
+ .tab {
132
+ border: none;
133
+ background: transparent;
134
+ color: var(--tab-text-inactive);
135
+ font-weight: 500;
136
+ cursor: pointer;
137
+ position: relative;
138
+ z-index: 1;
139
+ white-space: nowrap;
140
+ transition: color 0.15s ease;
141
+ padding: 0.625rem 1rem;
142
+ font-size: 0.95rem;
143
+ flex: 0 0 auto;
144
+ text-align: center;
145
+ }
146
+
147
+ [data-full-width="true"] .tab {
148
+ flex: 1;
149
+ }
150
+
151
+ .tab[data-active="true"] {
152
+ color: var(--tab-text-active);
153
+ }
154
+
155
+ [data-variant="underline"] .tab[data-active="true"] {
156
+ color: var(--tab-accent);
157
+ }
158
+
159
+ /* Sizes */
160
+ [data-size="sm"] .tab { padding: 0.4rem 0.75rem; font-size: 0.875rem; }
161
+ [data-size="lg"] .tab { padding: 0.75rem 1.25rem; font-size: 1rem; }
162
+
163
+ .panels {
164
+ margin-top: 1rem;
165
+ }
166
+
167
+ .panel {
168
+ display: none;
169
+ padding: 1rem;
170
+ background: #ffffff;
171
+ border-radius: 0.5rem;
172
+ }
173
+
174
+ [data-show-border="true"] .panel {
175
+ border: 1px solid var(--tab-border);
176
+ }
177
+
178
+ .panel[data-active="true"] {
179
+ display: block;
180
+ animation: astroTabsFadeIn 0.2s ease;
181
+ }
182
+
183
+ @keyframes astroTabsFadeIn {
184
+ from { opacity: 0; transform: translateY(4px); }
185
+ to { opacity: 1; transform: translateY(0); }
186
+ }
187
+
188
+ @media (prefers-reduced-motion: reduce) {
189
+ .indicator, .tab, .panel[data-active="true"] {
190
+ transition: none !important;
191
+ animation: none !important;
192
+ }
193
+ }
194
+ </style>
195
+
196
+ <div
197
+ {...rest}
198
+ class:list={["astro-animated-tabs", className]}
199
+ data-astro-tabs
200
+ data-variant={variant}
201
+ data-size={size}
202
+ data-show-border={showBorder.toString()}
203
+ data-full-width={fullWidth.toString()}
204
+ data-default-tab={initialTab}
205
+ style={`--tabs-color: ${color}; --tabs-bg-inactive: ${backgroundColor}; --tabs-text-inactive: ${inactiveTextColor}; --tabs-text-active: ${activeTextColor || (variant === "pill" ? "#ffffff" : color)};`}
206
+ >
207
+ <div class="tablist" role="tablist" aria-label="Tabs" data-tablist>
208
+ <div class="indicator" data-indicator></div>
209
+ {
210
+ safeTabs.map((t) => (
211
+ <button
212
+ class="tab"
213
+ type="button"
214
+ role="tab"
215
+ data-tab
216
+ data-tab-id={t.id}
217
+ data-active={t.id === initialTab ? "true" : "false"}
218
+ aria-selected={t.id === initialTab ? "true" : "false"}
219
+ tabindex={t.id === initialTab ? 0 : -1}
220
+ >
221
+ {t.label}
222
+ </button>
223
+ ))
224
+ }
225
+ </div>
226
+
227
+ <div class="panels">
228
+ {
229
+ safeTabs.map((t) => (
230
+ <div
231
+ class="panel"
232
+ role="tabpanel"
233
+ data-panel
234
+ data-panel-id={t.id}
235
+ data-active={t.id === initialTab ? "true" : "false"}
236
+ hidden={t.id !== initialTab}
237
+ >
238
+ <Fragment set:html={panelHtmlById.get(t.id) ?? ""} />
239
+ </div>
240
+ ))
241
+ }
242
+ </div>
243
+ </div>
244
+
245
+ <script is:inline>
246
+ (function() {
247
+ if (typeof window === 'undefined') return;
248
+
249
+ var initialized = new WeakMap();
250
+
251
+ function enhanceTabs(root) {
252
+ if (initialized.has(root)) return;
253
+
254
+ var tablist = root.querySelector('[data-tablist]');
255
+ var indicator = root.querySelector('[data-indicator]');
256
+ var tabs = Array.from(root.querySelectorAll('[data-tab]'));
257
+ var panels = Array.from(root.querySelectorAll('[data-panel]'));
258
+
259
+ if (!tablist || !indicator || tabs.length === 0) return;
260
+
261
+ var activeIndex = tabs.findIndex(function(t) {
262
+ return t.dataset.tabId === root.dataset.defaultTab;
263
+ });
264
+ if (activeIndex === -1) activeIndex = 0;
265
+
266
+ function updateIndicator() {
267
+ if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
268
+
269
+ var activeTab = tabs[activeIndex];
270
+ if (!activeTab) return;
271
+
272
+ var listRect = tablist.getBoundingClientRect();
273
+ var tabRect = activeTab.getBoundingClientRect();
274
+
275
+ var x = tabRect.left - listRect.left + tablist.scrollLeft;
276
+ var w = tabRect.width;
277
+
278
+ root.style.setProperty('--indicator-x', x);
279
+ root.style.setProperty('--indicator-w', w);
280
+ root.dataset.ready = "true";
281
+ }
282
+
283
+ function setActive(index, focus) {
284
+ activeIndex = index;
285
+ tabs.forEach(function(t, i) {
286
+ var isActive = i === index;
287
+ t.dataset.active = isActive ? "true" : "false";
288
+ t.setAttribute('aria-selected', isActive ? "true" : "false");
289
+ t.tabIndex = isActive ? 0 : -1;
290
+ });
291
+
292
+ panels.forEach(function(p) {
293
+ var isActive = p.dataset.panelId === tabs[index].dataset.tabId;
294
+ p.dataset.active = isActive ? "true" : "false";
295
+ if (isActive) {
296
+ p.removeAttribute('hidden');
297
+ } else {
298
+ p.setAttribute('hidden', '');
299
+ }
300
+ });
301
+
302
+ updateIndicator();
303
+ if (focus) tabs[index].focus();
304
+ }
305
+
306
+ tablist.addEventListener('click', function(e) {
307
+ var btn = e.target.closest('[data-tab]');
308
+ if (!btn) return;
309
+ setActive(tabs.indexOf(btn), true);
310
+ });
311
+
312
+ tablist.addEventListener('keydown', function(e) {
313
+ if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
314
+ e.preventDefault();
315
+ setActive((activeIndex + 1) % tabs.length, true);
316
+ } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
317
+ e.preventDefault();
318
+ setActive((activeIndex - 1 + tabs.length) % tabs.length, true);
319
+ } else if (e.key === 'Home') {
320
+ e.preventDefault();
321
+ setActive(0, true);
322
+ } else if (e.key === 'End') {
323
+ e.preventDefault();
324
+ setActive(tabs.length - 1, true);
325
+ }
326
+ });
327
+
328
+ window.addEventListener('resize', updateIndicator);
329
+
330
+ // Initial update
331
+ setActive(activeIndex);
332
+ setTimeout(updateIndicator, 0);
333
+
334
+ var cleanupObserver = new MutationObserver(function() {
335
+ if (!document.contains(root)) {
336
+ window.removeEventListener('resize', updateIndicator);
337
+ cleanupObserver.disconnect();
338
+ initialized.delete(root);
339
+ }
340
+ });
341
+ cleanupObserver.observe(document.body, { childList: true, subtree: true });
342
+
343
+ initialized.set(root, true);
344
+ }
345
+
346
+ document.querySelectorAll('[data-astro-tabs]').forEach(enhanceTabs);
347
+ })();
348
+ </script>
@@ -0,0 +1,3 @@
1
+ export { default } from './AnimatedTabs.astro';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
@@ -0,0 +1,159 @@
1
+ ---
2
+ interface Props {
3
+ as?: "button" | "a";
4
+ href?: string;
5
+ label: string;
6
+ type?: "button" | "submit" | "reset";
7
+ class?: string;
8
+ }
9
+
10
+ const {
11
+ as = "button",
12
+ href,
13
+ label,
14
+ type = "button",
15
+ class: className = "",
16
+ } = Astro.props;
17
+ ---
18
+
19
+ <style>
20
+ /* ✅ CRITERION 7: CSS-FIRST */
21
+
22
+ [data-acta] {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ gap: 0.25rem;
26
+
27
+ border: none;
28
+ background: transparent;
29
+
30
+ cursor: pointer;
31
+ text-decoration: none;
32
+ color: black;
33
+
34
+ font-family:
35
+ Inter,
36
+ ui-sans-serif,
37
+ system-ui,
38
+ -apple-system,
39
+ BlinkMacSystemFont,
40
+ "Segoe UI",
41
+ Arial,
42
+ sans-serif;
43
+ }
44
+
45
+ .label {
46
+ position: relative;
47
+
48
+ padding-bottom: 0.5rem;
49
+ padding-right: 0.9375rem;
50
+
51
+ font-size: 0.875rem;
52
+ letter-spacing: 0.25rem;
53
+ text-transform: uppercase;
54
+ }
55
+
56
+ /* Underline */
57
+ .label::after {
58
+ content: "";
59
+
60
+ position: absolute;
61
+ left: 0;
62
+ bottom: 0;
63
+
64
+ width: 100%;
65
+ height: 2px;
66
+
67
+ background: currentColor;
68
+
69
+ transform: scaleX(0);
70
+ transform-origin: bottom right;
71
+
72
+ transition: transform 250ms ease-out;
73
+ }
74
+
75
+ [data-acta]:hover .label::after {
76
+ transform: scaleX(1);
77
+ transform-origin: bottom left;
78
+ }
79
+
80
+ .arrow {
81
+ width: 1.875rem;
82
+ height: 0.625rem;
83
+
84
+ transform: translateX(-0.5rem);
85
+
86
+ transition: transform 300ms ease;
87
+ }
88
+
89
+ [data-acta]:hover .arrow {
90
+ transform: translateX(0);
91
+ }
92
+
93
+ [data-acta]:active .arrow {
94
+ transform: scale(0.9);
95
+ }
96
+
97
+ /* Accessibility */
98
+ [data-acta]:focus-visible {
99
+ outline: 2px solid currentColor;
100
+ outline-offset: 4px;
101
+ }
102
+
103
+ /* ✅ CRITERION 6: REDUCED MOTION */
104
+ @media (prefers-reduced-motion: reduce) {
105
+ [data-acta],
106
+ [data-acta] * {
107
+ transition: none !important;
108
+ transform: none !important;
109
+ }
110
+ }
111
+ </style>
112
+
113
+ {as === "a" ? (
114
+ <a
115
+ data-acta
116
+ href={href}
117
+ class={className}
118
+ aria-label={label}
119
+ >
120
+ <span class="label">{label}</span>
121
+
122
+ <svg
123
+ class="arrow"
124
+ aria-hidden="true"
125
+ xmlns="http://www.w3.org/2000/svg"
126
+ viewBox="0 0 46 16"
127
+ fill="none"
128
+ >
129
+ <path
130
+ d="M8,0,6.545,1.455l5.506,5.506H-30V9.039H12.052L6.545,14.545,8,16l8-8Z"
131
+ transform="translate(30)"
132
+ fill="currentColor"
133
+ />
134
+ </svg>
135
+ </a>
136
+ ) : (
137
+ <button
138
+ data-acta
139
+ type={type}
140
+ class={className}
141
+ aria-label={label}
142
+ >
143
+ <span class="label">{label}</span>
144
+
145
+ <svg
146
+ class="arrow"
147
+ aria-hidden="true"
148
+ xmlns="http://www.w3.org/2000/svg"
149
+ viewBox="0 0 46 16"
150
+ fill="none"
151
+ >
152
+ <path
153
+ d="M8,0,6.545,1.455l5.506,5.506H-30V9.039H12.052L6.545,14.545,8,16l8-8Z"
154
+ transform="translate(30)"
155
+ fill="currentColor"
156
+ />
157
+ </svg>
158
+ </button>
159
+ )}