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.
- package/CHANGELOG.md +42 -0
- package/ab-brand/index.tsx +30 -1
- package/ab-brand/styles.module.css +40 -1
- package/ab-button/helpers.ts +90 -0
- package/ab-button/index.tsx +164 -87
- package/ab-button/styles.module.css +79 -1
- package/ab-carousel/helpers.ts +146 -0
- package/ab-carousel/index.tsx +643 -0
- package/ab-carousel/styles.module.css +206 -0
- package/ab-chip/index.tsx +75 -0
- package/ab-chip/styles.module.css +87 -0
- package/ab-collapsible/index.tsx +30 -1
- package/ab-collapsible/styles.module.css +40 -1
- package/ab-flow-diagram/helpers.ts +77 -0
- package/ab-flow-diagram/index.tsx +141 -0
- package/ab-flow-diagram/styles.module.css +141 -0
- package/ab-icon/builtin.ts +61 -0
- package/ab-icon/helpers.ts +102 -0
- package/ab-icon/index.tsx +77 -16
- package/ab-icon/styles.module.css +53 -9
- package/ab-icon-button/index.tsx +110 -46
- package/ab-icon-button/styles.module.css +28 -10
- package/ab-install-snippet/helpers.ts +62 -0
- package/ab-install-snippet/index.tsx +170 -0
- package/ab-install-snippet/styles.module.css +104 -0
- package/ab-like-button/index.tsx +33 -1
- package/ab-like-button/styles.module.css +41 -6
- package/ab-linear-progress/index.tsx +129 -0
- package/ab-linear-progress/styles.module.css +105 -0
- package/ab-locale-switcher/index.tsx +213 -0
- package/ab-locale-switcher/styles.module.css +127 -0
- package/ab-logo/index.tsx +88 -30
- package/ab-logo/styles.module.css +79 -11
- package/ab-pill/index.tsx +74 -0
- package/ab-progress-chips/index.tsx +30 -1
- package/ab-progress-chips/styles.module.css +40 -1
- package/ab-searchbar/index.tsx +33 -2
- package/ab-searchbar/styles.module.css +41 -5
- package/ab-splash/csp.d.ts +54 -0
- package/ab-splash/csp.mjs +82 -0
- package/ab-splash/csp.ts +60 -0
- package/ab-splash/gate.ts +216 -0
- package/ab-splash/index.tsx +140 -0
- package/ab-splash/styles.module.css +103 -0
- package/ab-theme-toggle/index.tsx +188 -0
- package/ab-theme-toggle/styles.module.css +89 -0
- package/css/dialog.css +38 -3
- package/index.ts +47 -0
- package/package.json +46 -18
- package/server/ab-brand/index.tsx +29 -1
- package/server/ab-brand/styles.module.css +40 -1
- package/server/ab-button/index.tsx +96 -79
- package/server/ab-button/styles.module.css +79 -1
- package/server/ab-icon/index.tsx +68 -16
- package/server/ab-icon/styles.module.css +53 -9
- package/server/ab-logo/index.tsx +88 -29
- package/server/ab-logo/styles.module.css +79 -11
- package/types/css.d.ts +43 -0
- 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('')
|