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,146 @@
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 - Helpers (server-safe)
28
+ * @file: ab-carousel/helpers.ts
29
+ * @type: Pure TypeScript (no React, no 'use client')
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
+ *
32
+ * Example usage:
33
+ * 1+|> import { AB_CAROUSEL_NOSCRIPT_CSS } from 'ab-nextjs-components/ab-carousel/helpers'
34
+ * -|> <noscript><style>{AB_CAROUSEL_NOSCRIPT_CSS}</style></noscript> // ๐Ÿ“œ no-JS: stack every slide
35
+ */
36
+
37
+ /*
38
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
39
+ * MOTTO: We'll always do more ๐Ÿ˜œ!!!
40
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
41
+ */
42
+
43
+ // ๐Ÿงญ reading direction used for keyboard + swipe mapping
44
+ export type AbCarouselDir = 'ltr' | 'rtl'
45
+
46
+ // ๐ŸŽฌ what a key press asks the carousel to do
47
+ export type AbCarouselKeyAction = 'next' | 'prev' | 'first' | 'last'
48
+
49
+ // ๐Ÿ“ฃ why the index changed (handy for analytics, URL sync and focus decisions)
50
+ // โญ๏ธ 'skip' = Welcome Skip โ†’ LAST slide (God, ยง8 Q3); apps move focus to that slide's h1 on it
51
+ export type AbCarouselChangeReason = 'next' | 'prev' | 'dot' | 'key' | 'swipe' | 'skip' | 'api'
52
+
53
+ // ๐Ÿ“ where a slide sits relative to the active one (drives the CSS enter / exit offset)
54
+ export type AbCarouselSlidePosition = 'before' | 'active' | 'after'
55
+
56
+ // ๐Ÿท๏ธ default slide label: "3 of 9" (brief ยง5: aria-label on each role=group slide)
57
+ export const defaultAbCarouselSlideLabel = (n: number, total: number): string => `${n} of ${total}`
58
+
59
+ // ๐Ÿ“ฃ default live-region text: "Slide 3 of 9: Ready-made components" (title optional)
60
+ export const defaultAbCarouselAnnouncement = (n: number, total: number, title?: string): string =>
61
+ // ๐Ÿงฉ add the title only when we have one
62
+ title ? `Slide ${n} of ${total}: ${title}` : `Slide ${n} of ${total}`
63
+
64
+ // ๐Ÿ”˜ default dot label: "Go to slide 3: Ready-made components"
65
+ export function defaultAbCarouselDotLabel(n: number, total: number, title?: string): string {
66
+ void total // ๐Ÿงฉ unused by the default, but part of the signature for i18n callers ("{n} / {total}")
67
+ // ๐Ÿท๏ธ with or without the slide title
68
+ return title ? `Go to slide ${n}: ${title}` : `Go to slide ${n}`
69
+ }
70
+
71
+ // 0๏ธโƒฃ two-digit zero padding used by the counter ("02 / 09")
72
+ export const padAbCarouselNumber = (value: number): string => String(value).padStart(2, '0')
73
+
74
+ /**
75
+ * ๐Ÿ”’ clampAbCarouselIndex โ€” keep an index inside [0, count - 1].
76
+ * - ๐Ÿ” `loop: true` wraps around (โˆ’1 โ†’ last, count โ†’ 0)
77
+ * - ๐Ÿงฏ non-finite values โ†’ 0, `count <= 0` โ†’ 0
78
+ */
79
+ export function clampAbCarouselIndex(index: number, count: number, loop = false): number {
80
+ // ๐Ÿšซ empty carousel
81
+ if (!Number.isFinite(count) || count <= 0) return 0
82
+ // ๐Ÿšซ garbage index
83
+ if (!Number.isFinite(index)) return 0
84
+ // ๐Ÿ”ข integers only
85
+ const i = Math.trunc(index)
86
+ // ๐Ÿ” wrap (positive modulo)
87
+ if (loop) return ((i % count) + count) % count
88
+ // โœ‚๏ธ clamp
89
+ return Math.min(count - 1, Math.max(0, i))
90
+ }
91
+
92
+ /**
93
+ * โŒจ๏ธ getAbCarouselKeyAction โ€” map a `KeyboardEvent.key` to a carousel action.
94
+ * โ†/โ†’ follow the reading direction (RTL flips them); Home / End jump to the ends.
95
+ */
96
+ export function getAbCarouselKeyAction(key: string, dir: AbCarouselDir = 'ltr'): AbCarouselKeyAction | null {
97
+ // ๐Ÿ” RTL flips the arrows
98
+ const rtl = dir === 'rtl'
99
+ // ๐Ÿ—บ๏ธ the map
100
+ switch (key) {
101
+ case 'ArrowRight': return rtl ? 'prev' : 'next' // โžก๏ธ
102
+ case 'ArrowLeft': return rtl ? 'next' : 'prev' // โฌ…๏ธ
103
+ case 'Home': return 'first' // โฎ๏ธ
104
+ case 'End': return 'last' // โญ๏ธ
105
+ default: return null // ๐Ÿ™… not ours
106
+ }
107
+ }
108
+
109
+ // ๐Ÿ“ slide position relative to the active index
110
+ export function getAbCarouselSlidePosition(slide: number, active: number): AbCarouselSlidePosition {
111
+ // โฌ…๏ธ / โœ… / โžก๏ธ
112
+ return slide < active ? 'before' : slide > active ? 'after' : 'active'
113
+ }
114
+
115
+ /**
116
+ * โŒจ๏ธ Keyboard is ignored while focus is inside these (they own the arrow keys themselves):
117
+ * form fields, editable text, tablists (install box), sliders, listboxes, menus, radio groups,
118
+ * and anything marked `data-ab-keys-ignore`.
119
+ */
120
+ export const AB_CAROUSEL_KEY_IGNORE_SELECTOR = [
121
+ 'input', // โœ๏ธ text fields
122
+ 'textarea', // ๐Ÿ“
123
+ 'select', // ๐Ÿ”ฝ
124
+ '[contenteditable=""]', // โœ๏ธ
125
+ '[contenteditable="true"]', // โœ๏ธ
126
+ '[role="tablist"]', // ๐Ÿ—‚๏ธ install-box tabs use โ†/โ†’ for roving focus
127
+ '[role="slider"]', // ๐ŸŽš๏ธ
128
+ '[role="listbox"]', // ๐Ÿ“‹
129
+ '[role="menu"]', // ๐Ÿ”
130
+ '[role="radiogroup"]', // ๐Ÿ”˜ theme switch
131
+ '[data-ab-keys-ignore]', // ๐Ÿ™ˆ opt-out
132
+ ].join(',')
133
+
134
+ /**
135
+ * ๐Ÿ“œ No-JS stylesheet: put it in `<noscript><style>โ€ฆ</style></noscript>` on the page.
136
+ * Every slide is shown as a vertical stack and the JS-only controls are hidden (brief ยง1.3).
137
+ * Uses `data-ab-part` selectors (CSS-module class names are hashed).
138
+ */
139
+ export const AB_CAROUSEL_NOSCRIPT_CSS = [
140
+ // ๐Ÿ“š stack slides instead of overlaying them
141
+ '[data-ab-part="carousel"] [data-ab-part="track"]{display:block!important}',
142
+ // ๐Ÿ‘€ every slide visible, static, interactive
143
+ '[data-ab-part="carousel"] [data-ab-part="slide"]{opacity:1!important;visibility:visible!important;transform:none!important;pointer-events:auto!important}',
144
+ // ๐Ÿ™ˆ controls need JS
145
+ '[data-ab-part="carousel"] :is([data-ab-part="dots"],[data-ab-part="prev"],[data-ab-part="next"],[data-ab-part="counter"]){display:none!important}',
146
+ ].join('')