@ship-it-ui/ui 0.0.10 → 0.0.12
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/index.cjs +139 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -11
- package/dist/index.d.ts +50 -11
- package/dist/index.js +140 -38
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -3251,27 +3251,42 @@ var Carousel = (0, import_react52.forwardRef)(function Carousel2({
|
|
|
3251
3251
|
aspectRatio = 16 / 10,
|
|
3252
3252
|
showDots = true,
|
|
3253
3253
|
showArrows = true,
|
|
3254
|
+
loop = false,
|
|
3254
3255
|
className,
|
|
3255
3256
|
"aria-label": ariaLabel = "Carousel",
|
|
3256
3257
|
...props
|
|
3257
3258
|
}, ref) {
|
|
3259
|
+
const N = items.length;
|
|
3260
|
+
const loopMode = !loop ? null : loop === true ? "circular" : loop;
|
|
3261
|
+
const isLooping = loopMode !== null && N > 1;
|
|
3258
3262
|
const [active, setActive] = useControllableState({
|
|
3259
3263
|
value: indexProp,
|
|
3260
3264
|
defaultValue: defaultIndex ?? 0,
|
|
3261
3265
|
onChange: onIndexChange
|
|
3262
3266
|
});
|
|
3263
3267
|
const viewportRef = (0, import_react52.useRef)(null);
|
|
3268
|
+
const internalScrollRef = (0, import_react52.useRef)(false);
|
|
3269
|
+
const wrapInProgressRef = (0, import_react52.useRef)(false);
|
|
3270
|
+
const activeIdx = active ?? 0;
|
|
3271
|
+
const domIndexFor = (0, import_react52.useCallback)((real) => isLooping ? real + 1 : real, [isLooping]);
|
|
3264
3272
|
const goTo = (0, import_react52.useCallback)(
|
|
3265
3273
|
(i) => {
|
|
3266
|
-
const
|
|
3267
|
-
setActive(
|
|
3274
|
+
const next = isLooping ? (i % N + N) % N : Math.max(0, Math.min(N - 1, i));
|
|
3275
|
+
setActive(next);
|
|
3268
3276
|
const node = viewportRef.current;
|
|
3269
3277
|
if (node) {
|
|
3270
|
-
const
|
|
3271
|
-
|
|
3278
|
+
const isNextWrap = loopMode === "circular" && activeIdx === N - 1 && i === activeIdx + 1;
|
|
3279
|
+
const isPrevWrap = loopMode === "circular" && activeIdx === 0 && i === activeIdx - 1;
|
|
3280
|
+
const targetDom = isNextWrap ? N + 1 : isPrevWrap ? 0 : domIndexFor(next);
|
|
3281
|
+
const slide = node.children[targetDom];
|
|
3282
|
+
if (slide) {
|
|
3283
|
+
internalScrollRef.current = true;
|
|
3284
|
+
if (isNextWrap || isPrevWrap) wrapInProgressRef.current = true;
|
|
3285
|
+
slide.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "start" });
|
|
3286
|
+
}
|
|
3272
3287
|
}
|
|
3273
3288
|
},
|
|
3274
|
-
[
|
|
3289
|
+
[N, isLooping, loopMode, domIndexFor, setActive, activeIdx]
|
|
3275
3290
|
);
|
|
3276
3291
|
(0, import_react52.useEffect)(() => {
|
|
3277
3292
|
const node = viewportRef.current;
|
|
@@ -3279,13 +3294,64 @@ var Carousel = (0, import_react52.forwardRef)(function Carousel2({
|
|
|
3279
3294
|
const onScroll = () => {
|
|
3280
3295
|
const width = node.clientWidth;
|
|
3281
3296
|
if (width === 0) return;
|
|
3282
|
-
const
|
|
3283
|
-
if (
|
|
3297
|
+
const domIdx = Math.round(node.scrollLeft / width);
|
|
3298
|
+
if (!isLooping) {
|
|
3299
|
+
if (domIdx !== activeIdx) setActive(domIdx);
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
if (domIdx === 0) {
|
|
3303
|
+
if (wrapInProgressRef.current && node.scrollLeft > 1) return;
|
|
3304
|
+
const realTwin = node.children[N];
|
|
3305
|
+
if (realTwin) {
|
|
3306
|
+
internalScrollRef.current = true;
|
|
3307
|
+
realTwin.scrollIntoView({ behavior: "instant", block: "nearest", inline: "start" });
|
|
3308
|
+
}
|
|
3309
|
+
if (activeIdx !== N - 1) setActive(N - 1);
|
|
3310
|
+
wrapInProgressRef.current = false;
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3313
|
+
if (domIdx === N + 1) {
|
|
3314
|
+
if (wrapInProgressRef.current && node.scrollLeft < (N + 1) * width - 1) return;
|
|
3315
|
+
const realTwin = node.children[1];
|
|
3316
|
+
if (realTwin) {
|
|
3317
|
+
internalScrollRef.current = true;
|
|
3318
|
+
realTwin.scrollIntoView({ behavior: "instant", block: "nearest", inline: "start" });
|
|
3319
|
+
}
|
|
3320
|
+
if (activeIdx !== 0) setActive(0);
|
|
3321
|
+
wrapInProgressRef.current = false;
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
if (wrapInProgressRef.current) return;
|
|
3325
|
+
const realIdx = domIdx - 1;
|
|
3326
|
+
if (realIdx !== activeIdx) setActive(realIdx);
|
|
3284
3327
|
};
|
|
3285
3328
|
node.addEventListener("scroll", onScroll, { passive: true });
|
|
3286
3329
|
return () => node.removeEventListener("scroll", onScroll);
|
|
3287
|
-
}, [
|
|
3288
|
-
|
|
3330
|
+
}, [activeIdx, isLooping, N, setActive]);
|
|
3331
|
+
(0, import_react52.useEffect)(() => {
|
|
3332
|
+
if (internalScrollRef.current) {
|
|
3333
|
+
internalScrollRef.current = false;
|
|
3334
|
+
return;
|
|
3335
|
+
}
|
|
3336
|
+
const node = viewportRef.current;
|
|
3337
|
+
if (!node) return;
|
|
3338
|
+
const width = node.clientWidth;
|
|
3339
|
+
if (width === 0) return;
|
|
3340
|
+
const targetDom = domIndexFor(activeIdx);
|
|
3341
|
+
const currentDom = Math.round(node.scrollLeft / width);
|
|
3342
|
+
if (currentDom === targetDom) return;
|
|
3343
|
+
const slide = node.children[targetDom];
|
|
3344
|
+
slide?.scrollIntoView({ behavior: "instant", block: "nearest", inline: "start" });
|
|
3345
|
+
}, [activeIdx, domIndexFor]);
|
|
3346
|
+
(0, import_react52.useLayoutEffect)(() => {
|
|
3347
|
+
if (!isLooping) return;
|
|
3348
|
+
const node = viewportRef.current;
|
|
3349
|
+
if (!node) return;
|
|
3350
|
+
const slide = node.children[domIndexFor(activeIdx)];
|
|
3351
|
+
if (!slide) return;
|
|
3352
|
+
internalScrollRef.current = true;
|
|
3353
|
+
slide.scrollIntoView({ behavior: "instant", block: "nearest", inline: "start" });
|
|
3354
|
+
}, [isLooping]);
|
|
3289
3355
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3290
3356
|
"div",
|
|
3291
3357
|
{
|
|
@@ -3297,34 +3363,58 @@ var Carousel = (0, import_react52.forwardRef)(function Carousel2({
|
|
|
3297
3363
|
...props,
|
|
3298
3364
|
children: [
|
|
3299
3365
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "relative overflow-hidden rounded-md", children: [
|
|
3300
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
3366
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3301
3367
|
"div",
|
|
3302
3368
|
{
|
|
3303
3369
|
ref: viewportRef,
|
|
3304
3370
|
className: "flex w-full snap-x snap-mandatory overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
3305
3371
|
"aria-live": "polite",
|
|
3306
|
-
children:
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3372
|
+
children: [
|
|
3373
|
+
isLooping && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3374
|
+
"div",
|
|
3375
|
+
{
|
|
3376
|
+
"aria-hidden": "true",
|
|
3377
|
+
tabIndex: -1,
|
|
3378
|
+
className: "w-full shrink-0 snap-start",
|
|
3379
|
+
style: { aspectRatio: String(aspectRatio) },
|
|
3380
|
+
children: renderItem(items[N - 1], N - 1)
|
|
3381
|
+
},
|
|
3382
|
+
"clone-start"
|
|
3383
|
+
),
|
|
3384
|
+
items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3385
|
+
"div",
|
|
3386
|
+
{
|
|
3387
|
+
className: "w-full shrink-0 snap-start",
|
|
3388
|
+
style: { aspectRatio: String(aspectRatio) },
|
|
3389
|
+
role: "group",
|
|
3390
|
+
"aria-roledescription": "slide",
|
|
3391
|
+
"aria-label": `${i + 1} of ${N}`,
|
|
3392
|
+
children: renderItem(item, i)
|
|
3393
|
+
},
|
|
3394
|
+
i
|
|
3395
|
+
)),
|
|
3396
|
+
isLooping && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3397
|
+
"div",
|
|
3398
|
+
{
|
|
3399
|
+
"aria-hidden": "true",
|
|
3400
|
+
tabIndex: -1,
|
|
3401
|
+
className: "w-full shrink-0 snap-start",
|
|
3402
|
+
style: { aspectRatio: String(aspectRatio) },
|
|
3403
|
+
children: renderItem(items[0], 0)
|
|
3404
|
+
},
|
|
3405
|
+
"clone-end"
|
|
3406
|
+
)
|
|
3407
|
+
]
|
|
3318
3408
|
}
|
|
3319
3409
|
),
|
|
3320
|
-
showArrows &&
|
|
3410
|
+
showArrows && N > 1 && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
3321
3411
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3322
3412
|
"button",
|
|
3323
3413
|
{
|
|
3324
3414
|
type: "button",
|
|
3325
3415
|
"aria-label": "Previous slide",
|
|
3326
3416
|
onClick: () => goTo(activeIdx - 1),
|
|
3327
|
-
disabled: activeIdx === 0,
|
|
3417
|
+
disabled: !isLooping && activeIdx === 0,
|
|
3328
3418
|
className: "bg-panel/85 border-border text-text hover:bg-panel absolute top-1/2 left-2 inline-grid h-9 w-9 -translate-y-1/2 cursor-pointer place-items-center rounded-full border shadow-md backdrop-blur disabled:cursor-not-allowed disabled:opacity-40",
|
|
3329
3419
|
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_icons5.IconGlyph, { name: "caretLeft", size: 16 })
|
|
3330
3420
|
}
|
|
@@ -3335,13 +3425,13 @@ var Carousel = (0, import_react52.forwardRef)(function Carousel2({
|
|
|
3335
3425
|
type: "button",
|
|
3336
3426
|
"aria-label": "Next slide",
|
|
3337
3427
|
onClick: () => goTo(activeIdx + 1),
|
|
3338
|
-
disabled: activeIdx ===
|
|
3428
|
+
disabled: !isLooping && activeIdx === N - 1,
|
|
3339
3429
|
className: "bg-panel/85 border-border text-text hover:bg-panel absolute top-1/2 right-2 inline-grid h-9 w-9 -translate-y-1/2 cursor-pointer place-items-center rounded-full border shadow-md backdrop-blur disabled:cursor-not-allowed disabled:opacity-40",
|
|
3340
3430
|
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_icons5.IconGlyph, { name: "caretRight", size: 16 })
|
|
3341
3431
|
}
|
|
3342
3432
|
)
|
|
3343
3433
|
] }),
|
|
3344
|
-
showDots &&
|
|
3434
|
+
showDots && N > 1 && /*
|
|
3345
3435
|
* Plain `<button>` + `aria-current` rather than the tabs pattern
|
|
3346
3436
|
* (`role="tablist" / "tab"`). The APG carousel pattern recommends
|
|
3347
3437
|
* this lighter semantic; the viewport's `aria-live="polite"`
|
|
@@ -4401,19 +4491,28 @@ var Lightbox = (0, import_react59.forwardRef)(function Lightbox2({
|
|
|
4401
4491
|
index,
|
|
4402
4492
|
defaultIndex,
|
|
4403
4493
|
onIndexChange,
|
|
4494
|
+
loop = false,
|
|
4404
4495
|
title = "Photo viewer"
|
|
4405
4496
|
}, ref) {
|
|
4497
|
+
const N = items.length;
|
|
4498
|
+
const isLooping = loop && N > 1;
|
|
4406
4499
|
const [active, setActive] = useControllableState({
|
|
4407
4500
|
value: index,
|
|
4408
4501
|
defaultValue: defaultIndex ?? 0,
|
|
4409
4502
|
onChange: onIndexChange
|
|
4410
4503
|
});
|
|
4411
4504
|
const goPrev = (0, import_react59.useCallback)(() => {
|
|
4412
|
-
setActive((prev) =>
|
|
4413
|
-
|
|
4505
|
+
setActive((prev) => {
|
|
4506
|
+
const p = prev ?? 0;
|
|
4507
|
+
return isLooping ? (p - 1 + N) % N : Math.max(0, p - 1);
|
|
4508
|
+
});
|
|
4509
|
+
}, [setActive, isLooping, N]);
|
|
4414
4510
|
const goNext = (0, import_react59.useCallback)(() => {
|
|
4415
|
-
setActive((prev) =>
|
|
4416
|
-
|
|
4511
|
+
setActive((prev) => {
|
|
4512
|
+
const p = prev ?? 0;
|
|
4513
|
+
return isLooping ? (p + 1) % N : Math.min(N - 1, p + 1);
|
|
4514
|
+
});
|
|
4515
|
+
}, [setActive, isLooping, N]);
|
|
4417
4516
|
const onKey = (0, import_react59.useCallback)(
|
|
4418
4517
|
(e) => {
|
|
4419
4518
|
if (e.key === "ArrowLeft") {
|
|
@@ -4453,7 +4552,7 @@ var Lightbox = (0, import_react59.forwardRef)(function Lightbox2({
|
|
|
4453
4552
|
type: "button",
|
|
4454
4553
|
"aria-label": "Previous photo",
|
|
4455
4554
|
onClick: goPrev,
|
|
4456
|
-
disabled: activeIdx === 0,
|
|
4555
|
+
disabled: !isLooping && activeIdx === 0,
|
|
4457
4556
|
className: "absolute top-1/2 left-4 inline-grid h-11 w-11 -translate-y-1/2 cursor-pointer place-items-center rounded-full bg-white/10 text-white hover:bg-white/20 disabled:cursor-not-allowed disabled:opacity-40",
|
|
4458
4557
|
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_icons7.IconGlyph, { name: "caretLeft", size: 20 })
|
|
4459
4558
|
}
|
|
@@ -4464,7 +4563,7 @@ var Lightbox = (0, import_react59.forwardRef)(function Lightbox2({
|
|
|
4464
4563
|
type: "button",
|
|
4465
4564
|
"aria-label": "Next photo",
|
|
4466
4565
|
onClick: goNext,
|
|
4467
|
-
disabled: activeIdx ===
|
|
4566
|
+
disabled: !isLooping && activeIdx === N - 1,
|
|
4468
4567
|
className: "absolute top-1/2 right-4 inline-grid h-11 w-11 -translate-y-1/2 cursor-pointer place-items-center rounded-full bg-white/10 text-white hover:bg-white/20 disabled:cursor-not-allowed disabled:opacity-40",
|
|
4469
4568
|
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_icons7.IconGlyph, { name: "caretRight", size: 20 })
|
|
4470
4569
|
}
|
|
@@ -4517,6 +4616,7 @@ var ListingCard = (0, import_react60.forwardRef)(function ListingCard2({
|
|
|
4517
4616
|
variant = "default",
|
|
4518
4617
|
photos,
|
|
4519
4618
|
renderPhoto,
|
|
4619
|
+
loop = true,
|
|
4520
4620
|
onClick,
|
|
4521
4621
|
hoverEffect,
|
|
4522
4622
|
title,
|
|
@@ -4563,6 +4663,7 @@ var ListingCard = (0, import_react60.forwardRef)(function ListingCard2({
|
|
|
4563
4663
|
Carousel,
|
|
4564
4664
|
{
|
|
4565
4665
|
items: photos,
|
|
4666
|
+
loop,
|
|
4566
4667
|
...isSpec ? {
|
|
4567
4668
|
index: photoIndex,
|
|
4568
4669
|
onIndexChange: setPhotoIndex,
|
|
@@ -4803,6 +4904,7 @@ var ListingDetail = (0, import_react61.forwardRef)(function ListingDetail2({
|
|
|
4803
4904
|
onOpenChange,
|
|
4804
4905
|
photos,
|
|
4805
4906
|
renderPhoto,
|
|
4907
|
+
loop = true,
|
|
4806
4908
|
title,
|
|
4807
4909
|
eyebrow,
|
|
4808
4910
|
description,
|
|
@@ -4872,6 +4974,7 @@ var ListingDetail = (0, import_react61.forwardRef)(function ListingDetail2({
|
|
|
4872
4974
|
items: photos,
|
|
4873
4975
|
index: galleryIndex,
|
|
4874
4976
|
onIndexChange: setGalleryIndex,
|
|
4977
|
+
loop,
|
|
4875
4978
|
...isSpec ? { showDots: false } : {},
|
|
4876
4979
|
"aria-label": typeof title === "string" ? `${title} photos` : "Listing photos",
|
|
4877
4980
|
renderItem: (src, i) => renderPhoto ? renderPhoto(src, i, "gallery") : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
@@ -5117,6 +5220,7 @@ var ListingDetail = (0, import_react61.forwardRef)(function ListingDetail2({
|
|
|
5117
5220
|
items: photos,
|
|
5118
5221
|
index: galleryIndex,
|
|
5119
5222
|
onIndexChange: setGalleryIndex,
|
|
5223
|
+
loop,
|
|
5120
5224
|
title: lightboxTitle,
|
|
5121
5225
|
renderItem: (src, i) => renderPhoto ? renderPhoto(src, i, "lightbox") : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("img", { src, alt: "", className: "max-h-[88vh] max-w-[92vw] object-contain" })
|
|
5122
5226
|
}
|
|
@@ -7408,11 +7512,9 @@ var Tree = (0, import_react88.forwardRef)(function Tree2({
|
|
|
7408
7512
|
return out;
|
|
7409
7513
|
}, [items, expandedSet]);
|
|
7410
7514
|
const [activeId, setActiveId] = (0, import_react88.useState)(null);
|
|
7411
|
-
(
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
}
|
|
7415
|
-
}, [activeId, flatVisible]);
|
|
7515
|
+
if (activeId && !flatVisible.some((f) => f.id === activeId)) {
|
|
7516
|
+
setActiveId(null);
|
|
7517
|
+
}
|
|
7416
7518
|
const tabStopId = (0, import_react88.useMemo)(() => {
|
|
7417
7519
|
if (activeId && flatVisible.some((f) => f.id === activeId)) return activeId;
|
|
7418
7520
|
if (value && flatVisible.some((f) => f.id === value)) return value;
|