@a4ui/core 0.31.0 → 0.31.1
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/dist/elements.css +3 -0
- package/dist/full.css +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2148 -2140
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/ui/CardSpread.tsx +18 -12
- package/src/ui/Carousel3D.tsx +28 -6
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// import '@a4ui/core/styles.css'
|
|
9
9
|
// import { Button, Card, Modal } from '@a4ui/core'
|
|
10
10
|
|
|
11
|
-
export const A4UI_VERSION = '0.31.
|
|
11
|
+
export const A4UI_VERSION = '0.31.1'
|
|
12
12
|
|
|
13
13
|
// Helpers (src/lib) — generic, framework-level utilities.
|
|
14
14
|
export { cn } from './lib/cn'
|
package/src/ui/CardSpread.tsx
CHANGED
|
@@ -176,21 +176,27 @@ export function CardSpread(props: CardSpreadProps): JSX.Element {
|
|
|
176
176
|
<div
|
|
177
177
|
role="group"
|
|
178
178
|
aria-label={props['aria-label']}
|
|
179
|
-
class={cn('relative
|
|
179
|
+
class={cn('relative mx-auto h-96 w-full max-w-lg', props.class)}
|
|
180
180
|
onPointerEnter={handleEnter}
|
|
181
181
|
onPointerLeave={handleLeave}
|
|
182
182
|
>
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
183
|
+
{/* The cards fan around this fixed, centered anchor while the wider root
|
|
184
|
+
above stays the (stable) hover zone: a fanned spread reaches far past
|
|
185
|
+
a single card's box, so anchoring the hit-area to one card made the
|
|
186
|
+
cards leave it and flicker enter/leave. */}
|
|
187
|
+
<div class="absolute left-1/2 top-1/2 h-56 w-40 -translate-x-1/2 -translate-y-1/2">
|
|
188
|
+
<For each={props.items}>
|
|
189
|
+
{(item, i) => (
|
|
190
|
+
<div
|
|
191
|
+
ref={(el) => (cardRefs[i()] = el)}
|
|
192
|
+
class="absolute inset-0 rounded-xl border border-border bg-card text-card-foreground shadow-sm will-change-transform"
|
|
193
|
+
style={{ transform: transformString(restTransform(i(), props.items.length)) }}
|
|
194
|
+
>
|
|
195
|
+
{item}
|
|
196
|
+
</div>
|
|
197
|
+
)}
|
|
198
|
+
</For>
|
|
199
|
+
</div>
|
|
194
200
|
</div>
|
|
195
201
|
)
|
|
196
202
|
}
|
package/src/ui/Carousel3D.tsx
CHANGED
|
@@ -201,19 +201,31 @@ export function Carousel3D(props: Carousel3DProps): JSX.Element {
|
|
|
201
201
|
|
|
202
202
|
// --- pointer drag: horizontal movement past a threshold advances one slide
|
|
203
203
|
// per threshold crossed, so a long drag can page through several slides. --
|
|
204
|
-
|
|
204
|
+
// Capture is DEFERRED until the pointer actually moves past a small
|
|
205
|
+
// threshold. Capturing on pointerdown (the old behaviour) retargeted the
|
|
206
|
+
// pointer to the stage and swallowed the `click` on the chevron buttons and
|
|
207
|
+
// any interactive slide content. A plain click no longer starts a drag, so
|
|
208
|
+
// those clicks work again.
|
|
205
209
|
let startX = 0
|
|
210
|
+
let pointerId: number | null = null
|
|
211
|
+
let captured = false
|
|
212
|
+
const CAPTURE_THRESHOLD = 8
|
|
206
213
|
const DRAG_THRESHOLD = 60
|
|
207
214
|
|
|
208
215
|
const onPointerDown = (e: PointerEvent): void => {
|
|
209
216
|
if (count() < 2) return
|
|
210
217
|
startX = e.clientX
|
|
211
|
-
|
|
212
|
-
|
|
218
|
+
pointerId = e.pointerId
|
|
219
|
+
captured = false
|
|
213
220
|
}
|
|
214
221
|
const onPointerMove = (e: PointerEvent): void => {
|
|
215
|
-
if (
|
|
222
|
+
if (pointerId === null) return
|
|
216
223
|
const dx = e.clientX - startX
|
|
224
|
+
if (!captured) {
|
|
225
|
+
if (Math.abs(dx) < CAPTURE_THRESHOLD) return
|
|
226
|
+
captured = true
|
|
227
|
+
;(e.currentTarget as HTMLElement).setPointerCapture(pointerId)
|
|
228
|
+
}
|
|
217
229
|
if (dx <= -DRAG_THRESHOLD) {
|
|
218
230
|
next()
|
|
219
231
|
startX = e.clientX
|
|
@@ -222,8 +234,16 @@ export function Carousel3D(props: Carousel3DProps): JSX.Element {
|
|
|
222
234
|
startX = e.clientX
|
|
223
235
|
}
|
|
224
236
|
}
|
|
225
|
-
const endDrag = (): void => {
|
|
226
|
-
|
|
237
|
+
const endDrag = (e: PointerEvent): void => {
|
|
238
|
+
if (pointerId !== null && captured) {
|
|
239
|
+
try {
|
|
240
|
+
;(e.currentTarget as HTMLElement).releasePointerCapture(pointerId)
|
|
241
|
+
} catch {
|
|
242
|
+
/* already released */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
pointerId = null
|
|
246
|
+
captured = false
|
|
227
247
|
}
|
|
228
248
|
|
|
229
249
|
return (
|
|
@@ -266,6 +286,7 @@ export function Carousel3D(props: Carousel3DProps): JSX.Element {
|
|
|
266
286
|
type="button"
|
|
267
287
|
aria-label="Previous slide"
|
|
268
288
|
disabled={count() === 0 || active() === 0}
|
|
289
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
269
290
|
onClick={prev}
|
|
270
291
|
class="absolute left-2 top-1/2 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-primary text-primary-foreground shadow transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-40"
|
|
271
292
|
>
|
|
@@ -275,6 +296,7 @@ export function Carousel3D(props: Carousel3DProps): JSX.Element {
|
|
|
275
296
|
type="button"
|
|
276
297
|
aria-label="Next slide"
|
|
277
298
|
disabled={count() === 0 || active() === count() - 1}
|
|
299
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
278
300
|
onClick={next}
|
|
279
301
|
class="absolute right-2 top-1/2 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-primary text-primary-foreground shadow transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-40"
|
|
280
302
|
>
|