ab-nextjs-components 0.1.8 โ†’ 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/ab-brand/index.tsx +30 -1
  3. package/ab-brand/styles.module.css +40 -1
  4. package/ab-button/helpers.ts +90 -0
  5. package/ab-button/index.tsx +164 -87
  6. package/ab-button/styles.module.css +79 -1
  7. package/ab-carousel/helpers.ts +146 -0
  8. package/ab-carousel/index.tsx +643 -0
  9. package/ab-carousel/styles.module.css +206 -0
  10. package/ab-chip/index.tsx +75 -0
  11. package/ab-chip/styles.module.css +87 -0
  12. package/ab-collapsible/index.tsx +30 -1
  13. package/ab-collapsible/styles.module.css +40 -1
  14. package/ab-flow-diagram/helpers.ts +77 -0
  15. package/ab-flow-diagram/index.tsx +141 -0
  16. package/ab-flow-diagram/styles.module.css +141 -0
  17. package/ab-icon/builtin.ts +61 -0
  18. package/ab-icon/helpers.ts +102 -0
  19. package/ab-icon/index.tsx +77 -16
  20. package/ab-icon/styles.module.css +53 -9
  21. package/ab-icon-button/index.tsx +110 -46
  22. package/ab-icon-button/styles.module.css +28 -10
  23. package/ab-install-snippet/helpers.ts +62 -0
  24. package/ab-install-snippet/index.tsx +170 -0
  25. package/ab-install-snippet/styles.module.css +104 -0
  26. package/ab-like-button/index.tsx +33 -1
  27. package/ab-like-button/styles.module.css +41 -6
  28. package/ab-linear-progress/index.tsx +129 -0
  29. package/ab-linear-progress/styles.module.css +105 -0
  30. package/ab-locale-switcher/index.tsx +213 -0
  31. package/ab-locale-switcher/styles.module.css +127 -0
  32. package/ab-logo/index.tsx +88 -30
  33. package/ab-logo/styles.module.css +79 -11
  34. package/ab-pill/index.tsx +74 -0
  35. package/ab-progress-chips/index.tsx +30 -1
  36. package/ab-progress-chips/styles.module.css +40 -1
  37. package/ab-searchbar/index.tsx +33 -2
  38. package/ab-searchbar/styles.module.css +41 -5
  39. package/ab-splash/csp.d.ts +54 -0
  40. package/ab-splash/csp.mjs +82 -0
  41. package/ab-splash/csp.ts +60 -0
  42. package/ab-splash/gate.ts +216 -0
  43. package/ab-splash/index.tsx +140 -0
  44. package/ab-splash/styles.module.css +103 -0
  45. package/ab-theme-toggle/index.tsx +188 -0
  46. package/ab-theme-toggle/styles.module.css +89 -0
  47. package/css/dialog.css +38 -3
  48. package/index.ts +47 -0
  49. package/package.json +46 -18
  50. package/server/ab-brand/index.tsx +29 -1
  51. package/server/ab-brand/styles.module.css +40 -1
  52. package/server/ab-button/index.tsx +96 -79
  53. package/server/ab-button/styles.module.css +79 -1
  54. package/server/ab-icon/index.tsx +68 -16
  55. package/server/ab-icon/styles.module.css +53 -9
  56. package/server/ab-logo/index.tsx +88 -29
  57. package/server/ab-logo/styles.module.css +79 -11
  58. package/types/css.d.ts +43 -0
  59. package/types/index.d.ts +2 -0
@@ -0,0 +1,206 @@
1
+ /*
2
+ * @license MIT
3
+ * ~~~~~~~~~~~~
4
+ * ab-nextjs-components
5
+ * ~~~~~~~~~~~~
6
+ * Copyright (c) 2026 Abraham Ukachi. The abElements Project.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the 'Software'), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * @project: ab-nextjs-components
27
+ * @name: AbCarousel - Component Stylesheet (plain CSS, Tailwind-independent)
28
+ * @file: ab-carousel/styles.module.css
29
+ * @type: CSS Module
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
+ */
32
+
33
+ /*
34
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
36
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
37
+ */
38
+
39
+ /* ๐ŸŽ›๏ธ Tunables (override on the carousel or any ancestor):
40
+ * --ab-carousel-duration slide step (default 280ms) โ†’ --ab-slide-step-duration (ab-nextjs-animations)
41
+ * --ab-carousel-ease easing (default cubic-bezier(.2,.8,.2,1)) โ†’ --ab-slide-step-easing
42
+ * --ab-carousel-shift enter / exit offset (default 24px) โ†’ --ab-slide-step-distance
43
+ * ๐ŸŽฌ all motion comes from ab-nextjs-animations (slide-step + motion); nothing animates in this file
44
+ * --ab-carousel-nav-size prev / next diameter (default 40px; 44px on mobile)
45
+ * --ab-carousel-dot-color inactive dot colour
46
+ * --ab-carousel-accent active dot + filled button colour (default --ab-primary)
47
+ */
48
+
49
+ /* ๐ŸŽ  region */
50
+ .carousel {
51
+ position: relative; /* ๐Ÿ“Œ anchor for the hidden live region */
52
+ /* ๐ŸŽ›๏ธ tokens handed to ab-nextjs-animations (slide-step + motion) */
53
+ --ab-slide-step-duration: var(--ab-carousel-duration, 280ms); /* โฑ๏ธ */
54
+ --ab-slide-step-easing: var(--ab-carousel-ease, cubic-bezier(0.2, 0.8, 0.2, 1)); /* ๐Ÿ“ˆ */
55
+ --ab-slide-step-distance: var(--ab-carousel-shift, 24px); /* โ†”๏ธ */
56
+ --ab-slide-step-flip: 1; /* ๐ŸŒ LTR */
57
+ --_accent: var(--ab-carousel-accent, var(--ab-primary, #a67c52)); /* ๐ŸŸค bronze */
58
+ }
59
+
60
+ /* ๐ŸŒ RTL: mirror the slide offsets */
61
+ .carousel[data-dir='rtl'] {
62
+ --ab-slide-step-flip: -1; /* ๐ŸŒ slide steps mirror */
63
+ }
64
+
65
+ /* ๐ŸŽž๏ธ track: every slide shares one grid cell โ†’ height = tallest slide (CLS 0) */
66
+ .track {
67
+ display: grid; /* ๐Ÿงฑ */
68
+ touch-action: pan-y; /* ๐Ÿ‘† vertical scroll stays native; horizontal moves reach useAbSwipe */
69
+ }
70
+
71
+ /* ๐Ÿ–ผ๏ธ slide (inactive by default; enter / leave motion = .ab-slide-step-in / -out from ab-nextjs-animations) */
72
+ .slide {
73
+ grid-area: 1 / 1; /* ๐Ÿงฑ stacked */
74
+ min-width: 0; /* ๐Ÿ“ allow long words to wrap */
75
+ opacity: 0; /* ๐Ÿ™ˆ */
76
+ visibility: hidden; /* ๐Ÿ™ˆ not focusable, not read (also before hydration) */
77
+ pointer-events: none; /* ๐Ÿšซ */
78
+ }
79
+
80
+ /* โœ… active slide */
81
+ .slide[data-position='active'] {
82
+ opacity: 1; /* ๐Ÿ‘€ */
83
+ visibility: visible; /* ๐Ÿ‘€ */
84
+ pointer-events: auto; /* ๐Ÿ–ฑ๏ธ */
85
+ }
86
+
87
+ /* โฎ๏ธโญ๏ธ round prev / next buttons */
88
+ .nav {
89
+ display: inline-flex; /* ๐ŸŽฏ center the icon */
90
+ align-items: center;
91
+ justify-content: center;
92
+ width: var(--ab-carousel-nav-size, 40px); /* ๐Ÿ“ โ‰ฅ 40 on laptop */
93
+ height: var(--ab-carousel-nav-size, 40px);
94
+ padding: 0;
95
+ margin: 0;
96
+ border-radius: 9999px; /* โšช */
97
+ border: 1px solid var(--ab-outline, color-mix(in srgb, currentColor 24%, transparent)); /* ๐Ÿ–Š๏ธ */
98
+ background: transparent;
99
+ color: var(--ab-on-surface, currentColor);
100
+ cursor: pointer;
101
+ /* ๐ŸŽจ hover / ๐Ÿค press motion: .ab-motion-interactive + .ab-motion-press (ab-nextjs-animations) */
102
+ }
103
+ .nav:hover {
104
+ background-color: color-mix(in srgb, currentColor 8%, transparent); /* ๐ŸŒซ๏ธ */
105
+ }
106
+ .nav[data-variant='filled'] {
107
+ border-color: transparent;
108
+ background: var(--_accent); /* ๐ŸŸค primary-filled next */
109
+ color: var(--ab-on-primary, #fff);
110
+ }
111
+ .nav[data-variant='filled']:hover {
112
+ background: color-mix(in srgb, var(--_accent) 88%, #000);
113
+ }
114
+ .nav[aria-disabled='true'] {
115
+ opacity: 0.4; /* ๐Ÿšฆ edge */
116
+ cursor: not-allowed;
117
+ }
118
+
119
+ /* ๐ŸŽฏ visible focus ring (theme focus-ring token when G18 lands) */
120
+ .nav:focus-visible,
121
+ .dot:focus-visible {
122
+ outline: 2px solid var(--ab-focus-ring, var(--_accent));
123
+ outline-offset: 2px;
124
+ }
125
+
126
+ /* โžก๏ธ the arrow icon (mirrors in RTL) */
127
+ .navIcon {
128
+ flex: none; /* ๐Ÿšซ squash (stroke comes from AbIcon weight 300 = 1.5) */
129
+ }
130
+ .carousel[data-dir='rtl'] .navIcon {
131
+ transform: scaleX(-1); /* ๐ŸŒ */
132
+ }
133
+
134
+ /* ๐Ÿ“ฑ mobile: 44ร—44 targets (brief ยง5) */
135
+ @media (max-width: 639px) {
136
+ .nav {
137
+ width: var(--ab-carousel-nav-size, 44px);
138
+ height: var(--ab-carousel-nav-size, 44px);
139
+ }
140
+ }
141
+
142
+ /* ๐Ÿ”˜ dots row */
143
+ .dots {
144
+ display: inline-flex;
145
+ align-items: center;
146
+ gap: 0;
147
+ }
148
+
149
+ /* ๐Ÿ”˜ one dot = a 24ร—24 button (WCAG 2.5.8) holding an 8px mark */
150
+ .dot {
151
+ display: inline-flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ min-width: 24px;
155
+ height: 24px;
156
+ padding: 0 4px;
157
+ margin: 0;
158
+ border: 0;
159
+ border-radius: 9999px;
160
+ background: transparent;
161
+ cursor: pointer;
162
+ }
163
+
164
+ /* โšช the visible mark */
165
+ .dotMark {
166
+ display: block;
167
+ width: 8px;
168
+ height: 8px;
169
+ border-radius: 9999px;
170
+ background: var(--ab-carousel-dot-color, color-mix(in srgb, currentColor 28%, transparent));
171
+ /* ๐Ÿ“ 8 โ†’ 24px motion: .ab-motion-size (ab-nextjs-animations) */
172
+ }
173
+
174
+ /* โœ… active = long bronze pill */
175
+ .dot[data-active='true'] .dotMark {
176
+ width: 24px;
177
+ background: var(--_accent);
178
+ }
179
+
180
+ /* โ™ฟ reduced motion (OS or reducedMotion prop) is handled by ab-nextjs-animations via data-ab-reduced-motion */
181
+
182
+ /* ๐Ÿ”ข counter "02 / 09" */
183
+ .counter {
184
+ font-family: var(--ab-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
185
+ font-size: 0.8125rem;
186
+ letter-spacing: 0.04em;
187
+ color: var(--ab-on-surface-variant, color-mix(in srgb, currentColor 64%, transparent));
188
+ }
189
+ .counter b {
190
+ font-weight: 700;
191
+ color: var(--ab-on-surface, currentColor);
192
+ }
193
+
194
+ /* ๐Ÿ™ˆ visually hidden but announced */
195
+ .srOnly {
196
+ position: absolute;
197
+ width: 1px;
198
+ height: 1px;
199
+ padding: 0;
200
+ margin: -1px;
201
+ overflow: hidden;
202
+ clip: rect(0 0 0 0);
203
+ clip-path: inset(50%);
204
+ white-space: nowrap;
205
+ border: 0;
206
+ }
@@ -0,0 +1,75 @@
1
+ /*
2
+ * @license MIT
3
+ * ~~~~~~~~~~~~
4
+ * ab-nextjs-components
5
+ * ~~~~~~~~~~~~
6
+ * Copyright (c) 2026 Abraham Ukachi. The abElements Project.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the 'Software'), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * @project: ab-nextjs-components
27
+ * @name: AbChip - Server (G36)
28
+ * @file: ab-chip/index.tsx
29
+ * @type: Server component (static, no JS)
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
+ *
32
+ * Example usage:
33
+ * 1+|> <ul><AbChip as="li" dot>Tokens</AbChip><AbChip as="li">Light &amp; dark</AbChip></ul>
34
+ */
35
+
36
+ /*
37
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
38
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
39
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
40
+ */
41
+
42
+ // โš›๏ธ types
43
+ import type { CSSProperties, ReactElement, ReactNode } from 'react';
44
+ // ๐Ÿงต classes
45
+ import clsx from 'clsx';
46
+ // ๐ŸŽจ styles
47
+ import styles from './styles.module.css';
48
+
49
+ // ๐ŸŽจ dot colours
50
+ export type AbChipDot = 'sage' | 'bronze';
51
+
52
+ // โš™๏ธ props
53
+ export interface AbChipProps {
54
+ children: ReactNode; // ๐Ÿท๏ธ text
55
+ dot?: boolean | AbChipDot; // ๐ŸŸข leading dot (true = bronze)
56
+ icon?: ReactNode; // ๐Ÿ–ผ๏ธ leading icon (decorative)
57
+ as?: 'span' | 'li'; // ๐Ÿงฑ 'li' inside a <ul> for lists of chips
58
+ className?: string; // ๐Ÿท๏ธ
59
+ style?: CSSProperties; // ๐ŸŽจ
60
+ }
61
+
62
+ /** ๐Ÿท๏ธ Static chip: plain text, never interactive (use AbButton for actions). */
63
+ export function AbChip({ children, dot, icon, as: Tag = 'span', className, style }: AbChipProps): ReactElement {
64
+ const tone = dot === true ? 'bronze' : dot || undefined; // ๐ŸŽจ resolve dot colour
65
+ return (
66
+ <Tag className={clsx('AbChip', styles.chip, className)} style={style} data-ab-part="chip">
67
+ {tone ? <span className={styles.dot} data-tone={tone} aria-hidden="true" /> : null /* ๐ŸŸข decorative */}
68
+ {icon ? <span className={styles.icon} aria-hidden="true">{icon}</span> : null /* ๐Ÿ–ผ๏ธ decorative */}
69
+ <span>{children}</span>
70
+ </Tag>
71
+ );
72
+ }
73
+
74
+ // ๐Ÿ“ฆ default export
75
+ export default AbChip;
@@ -0,0 +1,87 @@
1
+ /*
2
+ * @license MIT
3
+ * ~~~~~~~~~~~~
4
+ * ab-nextjs-components
5
+ * ~~~~~~~~~~~~
6
+ * Copyright (c) 2026 Abraham Ukachi. The abElements Project.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the 'Software'), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * @project: ab-nextjs-components
27
+ * @name: AbChip / AbPill - Styles
28
+ * @file: ab-chip/styles.module.css
29
+ * @type: CSS module
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
+ */
32
+
33
+ /*
34
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
36
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
37
+ */
38
+
39
+ /* ๐Ÿท๏ธ chip */
40
+ .chip {
41
+ display: inline-flex; /* ๐Ÿ“ */
42
+ align-items: center; /* โ†•๏ธ */
43
+ gap: 0.375rem; /* ๐Ÿงฑ */
44
+ padding: 0.25rem 0.75rem; /* ๐Ÿงฑ */
45
+ border-radius: 9999px; /* ๐Ÿ’Š */
46
+ border: 1px solid var(--ab-color-outline-variant, rgb(0 0 0 / 0.12)); /* ๐Ÿ–Š๏ธ */
47
+ background: var(--ab-color-surface-container, transparent); /* ๐ŸŽจ */
48
+ color: var(--ab-color-on-surface, currentColor); /* ๐ŸŽจ */
49
+ font-size: 0.875rem; /* ๐Ÿ”ก */
50
+ line-height: 1.4; /* ๐Ÿ“ */
51
+ white-space: nowrap; /* ๐Ÿšซ wrap */
52
+ list-style: none; /* ๐Ÿงน when as="li" */
53
+ }
54
+
55
+ /* ๐Ÿ’Š pill (eyebrow): small text โ†’ AA bronze text token in light mode */
56
+ .pill {
57
+ composes: chip; /* โ™ป๏ธ */
58
+ color: var(--ab-color-bronze-text, #8A6440); /* โ™ฟ 5.02:1 on #fff8f3 */
59
+ border-color: color-mix(in srgb, var(--ab-color-bronze, #A67C52) 35%, transparent); /* ๐Ÿ–Š๏ธ */
60
+ background: color-mix(in srgb, var(--ab-color-bronze, #A67C52) 8%, transparent); /* ๐ŸŽจ */
61
+ font-size: 0.8125rem; /* ๐Ÿ”ก */
62
+ font-weight: 600; /* ๐Ÿ’ช */
63
+ }
64
+
65
+ /* โŒจ๏ธ mono eyebrow (package names like ab-nextjs-core) */
66
+ .mono {
67
+ font-family: var(--ab-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace); /* ๐Ÿ”ค */
68
+ }
69
+
70
+ /* ๐ŸŸข dot */
71
+ .dot {
72
+ flex: none; /* ๐Ÿšซ squash */
73
+ width: 0.5rem; /* ๐Ÿ“ */
74
+ height: 0.5rem; /* ๐Ÿ“ */
75
+ border-radius: 50%; /* โšช */
76
+ background: var(--ab-color-bronze, #A67C52); /* ๐Ÿฅ‰ default */
77
+ }
78
+ .dot[data-tone='sage'] {
79
+ background: var(--ab-color-sage, #7C9A7E); /* ๐ŸŒฟ "live" / "free forever" */
80
+ }
81
+
82
+ /* ๐Ÿ–ผ๏ธ icon box */
83
+ .icon {
84
+ display: inline-flex; /* ๐Ÿ“ */
85
+ width: 1em; /* ๐Ÿ“ */
86
+ height: 1em; /* ๐Ÿ“ */
87
+ }
@@ -5,11 +5,38 @@
5
5
  * ~~~~~~~~~~~~
6
6
  * Copyright (c) 2026 Abraham Ukachi. The abElements Project.
7
7
  *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the 'Software'), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
8
26
  * @project: ab-nextjs-components
9
27
  * @name: AbCollapsible - Client (port of lyd-collapsible)
10
28
  * @file: ab-collapsible/index.tsx
29
+ * @type: TypeScript (React)
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
11
31
  */
12
32
 
33
+ /*
34
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
36
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
37
+ */
38
+
39
+
13
40
  'use client';
14
41
 
15
42
  import type { CSSProperties, ReactElement, ReactNode } from 'react';
@@ -17,6 +44,8 @@ import { useState } from 'react';
17
44
  import Link from 'next/link';
18
45
  import clsx from 'clsx';
19
46
  import styles from './styles.module.css';
47
+ import { AB_MOTION } from 'ab-nextjs-animations/motion'; // ๐ŸŽฌ transition class names (ab-nextjs-animations >= 0.2.4)
48
+ import 'ab-nextjs-animations/motion/styles.css'; // ๐ŸŽจ .ab-motion-*
20
49
 
21
50
  export interface AbCollapsibleProps {
22
51
  href?: string | null;
@@ -137,7 +166,7 @@ const AbCollapsible = ({
137
166
  </button>
138
167
  ) : null}
139
168
  <span
140
- className={clsx('material-symbols-rounded', styles.abCollapsibleExpand, open && styles.expanded)}
169
+ className={clsx('material-symbols-rounded', styles.abCollapsibleExpand, AB_MOTION.transform, open && styles.expanded)} // ๐Ÿ”„ rotation tween from ab-nextjs-animations
141
170
  aria-hidden
142
171
  >
143
172
  {expandIcon}
@@ -1,3 +1,42 @@
1
+ /*
2
+ * @license MIT
3
+ * ~~~~~~~~~~~~
4
+ * ab-nextjs-components
5
+ * ~~~~~~~~~~~~
6
+ * Copyright (c) 2026 Abraham Ukachi. The abElements Project.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the 'Software'), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * @project: ab-nextjs-components
27
+ * @name: ab-collapsible - styles
28
+ * @file: ab-collapsible/styles.module.css
29
+ * @type: CSS Module
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
+ */
32
+
33
+ /*
34
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
36
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
37
+ */
38
+
39
+
1
40
  .abCollapsible {
2
41
  display: flex;
3
42
  flex-direction: column;
@@ -79,7 +118,7 @@
79
118
  }
80
119
 
81
120
  .abCollapsibleExpand {
82
- transition: transform 0.2s ease;
121
+ /* ๐Ÿ”„ rotation tween = .ab-motion-transform (ab-nextjs-animations) */
83
122
  }
84
123
 
85
124
  .abCollapsibleExpand.expanded {
@@ -0,0 +1,77 @@
1
+ /*
2
+ * @license MIT
3
+ * ~~~~~~~~~~~~
4
+ * ab-nextjs-components
5
+ * ~~~~~~~~~~~~
6
+ * Copyright (c) 2026 Abraham Ukachi. The abElements Project.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the 'Software'), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * @project: ab-nextjs-components
27
+ * @name: AbFlowDiagram - Helpers (G38)
28
+ * @file: ab-flow-diagram/helpers.ts
29
+ * @type: TypeScript (pure, server-safe)
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
+ */
32
+
33
+ /*
34
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
36
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
37
+ */
38
+
39
+ // โš›๏ธ ReactNode for node icons
40
+ import type { ReactNode } from 'react';
41
+
42
+ // ๐Ÿ”ต a node (x/y in 0โ€“100 scene units)
43
+ export interface AbFlowNode {
44
+ id: string; // ๐Ÿ†”
45
+ label: string; // ๐Ÿท๏ธ visible text (package/component names are not translated)
46
+ x: number; // โ†”๏ธ 0โ€“100
47
+ y: number; // โ†•๏ธ 0โ€“100
48
+ icon?: ReactNode; // ๐Ÿ–ผ๏ธ e.g. <AbIcon name="widgets" />
49
+ tone?: 'hub' | 'node' | 'accent'; // ๐ŸŽจ hub = centre logo
50
+ }
51
+
52
+ // ใ€ฐ๏ธ a wire
53
+ export interface AbFlowEdge {
54
+ from: string; // ๐Ÿ”ต node id
55
+ to: string; // ๐Ÿ”ต node id
56
+ curve?: number; // ๐ŸŒ™ -1โ€ฆ1 bend (0 = straight)
57
+ }
58
+
59
+ // โœ‚๏ธ clamp into the scene
60
+ const clamp = (v: number) => Math.min(100, Math.max(0, v));
61
+
62
+ /**
63
+ * @name getAbFlowEdgePath
64
+ * @description ใ€ฐ๏ธ SVG path between two nodes: straight, or a quadratic curve bent sideways.
65
+ */
66
+ export function getAbFlowEdgePath(a: Pick<AbFlowNode, 'x' | 'y'>, b: Pick<AbFlowNode, 'x' | 'y'>, curve = 0): string {
67
+ const [x1, y1, x2, y2] = [clamp(a.x), clamp(a.y), clamp(b.x), clamp(b.y)]; // ๐Ÿ“
68
+ if (!curve) return `M ${x1} ${y1} L ${x2} ${y2}`; // โž– straight
69
+ const mx = (x1 + x2) / 2; // ๐ŸŽฏ midpoint
70
+ const my = (y1 + y2) / 2; // ๐ŸŽฏ
71
+ const dx = x2 - x1; // โ†”๏ธ
72
+ const dy = y2 - y1; // โ†•๏ธ
73
+ const k = Math.max(-1, Math.min(1, curve)) * 0.5; // ๐ŸŒ™ bend strength
74
+ const cx = mx - dy * k; // โคด๏ธ perpendicular offset
75
+ const cy = my + dx * k; // โคต๏ธ
76
+ return `M ${x1} ${y1} Q ${+cx.toFixed(2)} ${+cy.toFixed(2)} ${x2} ${y2}`; // ใ€ฐ๏ธ
77
+ }