@krizaka/ui 3.18.2 → 3.20.0
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/avatar/defaults.js +6 -1
- package/dist/avatar/defaults.js.map +1 -1
- package/dist/avatar.js +6 -1
- package/dist/avatar.js.map +1 -1
- package/dist/blocks.css +11 -0
- package/dist/card-grid.d.ts +14 -1
- package/dist/card-grid.js +29 -6
- package/dist/card-grid.js.map +1 -1
- package/dist/chat.d.ts +51 -3
- package/dist/chat.js +64 -32
- package/dist/chat.js.map +1 -1
- package/dist/{chunk-276PTQMQ.js → chunk-3BC4XQ6C.js} +2 -1
- package/dist/{chunk-YIBKJ36L.js → chunk-KB7OLYIJ.js} +7 -2
- package/dist/{chunk-YIBKJ36L.js.map → chunk-KB7OLYIJ.js.map} +1 -1
- package/dist/data-table.js +1 -1
- package/dist/file-upload.js +2 -2
- package/dist/file-upload.js.map +1 -1
- package/dist/match-dialog.js +2 -2
- package/dist/media-grid.d.ts +66 -3
- package/dist/media-grid.js +312 -65
- package/dist/media-grid.js.map +1 -1
- package/dist/native.js +6 -1
- package/dist/native.js.map +1 -1
- package/dist/progress.js +2 -2
- package/dist/progress.js.map +1 -1
- package/dist/vertical-video.d.ts +7 -1
- package/dist/vertical-video.js +7 -5
- package/dist/vertical-video.js.map +1 -1
- package/package.json +8 -8
- package/registry/achievement.json +16 -2
- package/registry/action-bar.json +16 -2
- package/registry/action-sheet.json +15 -0
- package/registry/activity-feed.json +13 -2
- package/registry/alert.json +15 -2
- package/registry/app-shell.json +15 -2
- package/registry/argument-card.json +16 -2
- package/registry/audio-player.json +15 -2
- package/registry/auth-layout.json +15 -2
- package/registry/avatar.json +14 -3
- package/registry/badge.json +13 -2
- package/registry/button.json +13 -2
- package/registry/card-grid.json +69 -4
- package/registry/card.json +13 -2
- package/registry/catalogue-page.json +15 -2
- package/registry/changelog-page.json +15 -2
- package/registry/chat.json +115 -10
- package/registry/checkbox.json +13 -2
- package/registry/chip-link.json +15 -2
- package/registry/chip.json +13 -2
- package/registry/choice-grid.json +16 -2
- package/registry/cn.json +12 -0
- package/registry/code-block.json +15 -2
- package/registry/combobox.json +13 -2
- package/registry/command.json +15 -2
- package/registry/component-page.json +15 -2
- package/registry/confirm-button.json +15 -2
- package/registry/contact-page.json +15 -2
- package/registry/continue-prompt.json +16 -2
- package/registry/countdown.json +13 -2
- package/registry/cta-panel.json +16 -2
- package/registry/dashboard-layout.json +15 -2
- package/registry/data-table.json +15 -2
- package/registry/date-picker.json +13 -2
- package/registry/decision-list.json +16 -2
- package/registry/description-list.json +13 -2
- package/registry/detail-layout.json +15 -2
- package/registry/dialog.json +13 -2
- package/registry/docs-article-page.json +15 -2
- package/registry/docs-hub-page.json +15 -2
- package/registry/docs-layout.json +15 -2
- package/registry/document-viewer.json +15 -2
- package/registry/dropdown-menu.json +15 -2
- package/registry/empty-state.json +13 -2
- package/registry/error-page.json +14 -2
- package/registry/examples/card-grid/foundation.d.ts +4 -0
- package/registry/examples/card-grid/foundation.js +38 -0
- package/registry/examples/card-grid/foundation.tsx +35 -0
- package/registry/examples/chat/conversation.js +2 -2
- package/registry/examples/chat/conversation.tsx +4 -3
- package/registry/examples/chat/pill-composer.d.ts +4 -0
- package/registry/examples/chat/pill-composer.js +34 -0
- package/registry/examples/chat/pill-composer.tsx +39 -0
- package/registry/examples/glow-card/plans.js +9 -12
- package/registry/examples/glow-card/plans.tsx +18 -14
- package/registry/examples/media-grid/loading.d.ts +4 -0
- package/registry/examples/media-grid/loading.js +28 -0
- package/registry/examples/media-grid/loading.tsx +25 -0
- package/registry/examples/vertical-video/rail.js +3 -2
- package/registry/examples/vertical-video/rail.tsx +4 -3
- package/registry/fab.json +15 -0
- package/registry/field.json +13 -2
- package/registry/file-upload.json +15 -2
- package/registry/filter-bar.json +15 -2
- package/registry/form.json +13 -2
- package/registry/gallery-page.json +15 -2
- package/registry/glow-card.json +18 -4
- package/registry/goal-gauge.json +13 -2
- package/registry/header.json +15 -0
- package/registry/how-it-works-page.json +15 -2
- package/registry/image-cropper.json +15 -2
- package/registry/image-viewer.json +15 -0
- package/registry/index.json +1773 -10
- package/registry/iso.json +15 -2
- package/registry/kanban.json +15 -2
- package/registry/kbd.json +14 -2
- package/registry/landing-page.json +15 -2
- package/registry/landscape.json +15 -2
- package/registry/legal-page.json +15 -2
- package/registry/link-card.json +16 -2
- package/registry/list.json +13 -2
- package/registry/loader.json +13 -2
- package/registry/longform-page.json +15 -2
- package/registry/map.json +14 -3
- package/registry/markdown.json +13 -2
- package/registry/marketing-layout.json +15 -2
- package/registry/marquee.json +15 -2
- package/registry/mascot-quote.json +16 -2
- package/registry/mascot-state.json +13 -2
- package/registry/mascots.json +13 -2
- package/registry/match-dialog.json +13 -2
- package/registry/media-capture.json +13 -2
- package/registry/media-grid.json +341 -13
- package/registry/media-picker.json +15 -0
- package/registry/meter.json +13 -2
- package/registry/nav-bar.json +17 -3
- package/registry/number-ticker.json +13 -2
- package/registry/onboarding.json +15 -0
- package/registry/otp-input.json +15 -0
- package/registry/page-header.json +15 -2
- package/registry/page-hero.json +16 -2
- package/registry/page.json +16 -2
- package/registry/pagination.json +13 -2
- package/registry/permission-prompt.json +15 -0
- package/registry/photo-grid.json +13 -2
- package/registry/pointer-light.json +15 -2
- package/registry/popover.json +15 -2
- package/registry/pricing-page.json +15 -2
- package/registry/product-page.json +15 -2
- package/registry/profile-card.json +13 -2
- package/registry/progress.json +14 -3
- package/registry/promise-card.json +16 -2
- package/registry/pull-to-refresh.json +15 -0
- package/registry/radio-group.json +13 -2
- package/registry/recipes.json +14 -2
- package/registry/screen.json +15 -0
- package/registry/scroll-stage.json +15 -2
- package/registry/search-field.json +13 -2
- package/registry/section-backdrop.json +15 -2
- package/registry/segmented.json +15 -0
- package/registry/separator.json +15 -2
- package/registry/settings-layout.json +15 -2
- package/registry/showcase.json +13 -2
- package/registry/site-footer.json +16 -3
- package/registry/sites.json +15 -2
- package/registry/skeleton.json +13 -2
- package/registry/skip-link.json +14 -2
- package/registry/slider.json +13 -2
- package/registry/slot.json +14 -2
- package/registry/spinner.json +13 -2
- package/registry/splash-handoff.json +15 -0
- package/registry/split-view.json +15 -2
- package/registry/stage-banner.json +15 -2
- package/registry/stat.json +15 -2
- package/registry/status-page.json +15 -2
- package/registry/step-progress.json +13 -2
- package/registry/stepper.json +13 -2
- package/registry/swipe-deck.json +13 -2
- package/registry/swipeable-row.json +15 -0
- package/registry/switch.json +13 -2
- package/registry/tab-bar.json +15 -0
- package/registry/tabs.json +13 -2
- package/registry/tag-input.json +15 -2
- package/registry/tag-selector.json +13 -2
- package/registry/terminal-replay.json +15 -2
- package/registry/theme.json +13 -2
- package/registry/toast.json +13 -2
- package/registry/toc.json +15 -2
- package/registry/tooltip.json +14 -2
- package/registry/tree-view.json +15 -2
- package/registry/txt.json +13 -0
- package/registry/verified-badge.json +13 -2
- package/registry/vertical-video.json +32 -6
- package/registry/video-player.json +13 -2
- package/registry/video-trimmer.json +15 -2
- package/registry/virtual.json +15 -2
- /package/dist/{chunk-276PTQMQ.js.map → chunk-3BC4XQ6C.js.map} +0 -0
package/dist/media-grid.js
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
import "./chunk-NPF3OHE2.js";
|
|
3
3
|
import {
|
|
4
4
|
Avatar
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KB7OLYIJ.js";
|
|
6
|
+
import "./chunk-JXLDUDTD.js";
|
|
7
|
+
import {
|
|
8
|
+
Button,
|
|
9
|
+
LoaderGlyph
|
|
10
|
+
} from "./chunk-3BC4XQ6C.js";
|
|
6
11
|
import {
|
|
7
12
|
defineRecipe
|
|
8
13
|
} from "./chunk-D3T54RSL.js";
|
|
@@ -10,11 +15,58 @@ import {
|
|
|
10
15
|
cn
|
|
11
16
|
} from "./chunk-2FRWNSRO.js";
|
|
12
17
|
|
|
13
|
-
// src/media-grid/
|
|
18
|
+
// src/media-grid/load-more.tsx
|
|
14
19
|
import * as React from "react";
|
|
15
20
|
|
|
16
|
-
// src/
|
|
21
|
+
// src/spinner/spinner.tsx
|
|
22
|
+
import { tv } from "tailwind-variants";
|
|
17
23
|
import { jsx } from "react/jsx-runtime";
|
|
24
|
+
var spinnerVariants = tv({
|
|
25
|
+
base: "shrink-0 text-accent",
|
|
26
|
+
variants: { size: { sm: "h-4 w-4", md: "h-6 w-6", lg: "h-10 w-10" } },
|
|
27
|
+
defaultVariants: { size: "md" }
|
|
28
|
+
});
|
|
29
|
+
function Spinner({ label, size, value, className, ...props }) {
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
LoaderGlyph,
|
|
32
|
+
{
|
|
33
|
+
role: "status",
|
|
34
|
+
"aria-label": label,
|
|
35
|
+
"aria-hidden": void 0,
|
|
36
|
+
value,
|
|
37
|
+
"data-size": size ?? "md",
|
|
38
|
+
className: spinnerVariants({ size, className }),
|
|
39
|
+
...props
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/media-grid/load-more.tsx
|
|
45
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
46
|
+
function LoadMore({ onLoadMore, hasMore, loading = false, failed = false, label, loadingLabel, retryLabel, endLabel, rootMargin = "900px 0px", className, ...props }) {
|
|
47
|
+
const sentinel = React.useRef(null);
|
|
48
|
+
const ask = React.useRef(onLoadMore);
|
|
49
|
+
React.useEffect(() => {
|
|
50
|
+
ask.current = onLoadMore;
|
|
51
|
+
});
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
const el = sentinel.current;
|
|
54
|
+
if (!el || !hasMore || loading || failed || typeof IntersectionObserver === "undefined") return;
|
|
55
|
+
const io = new IntersectionObserver((entries) => entries.some((e) => e.isIntersecting) && ask.current(), { rootMargin });
|
|
56
|
+
io.observe(el);
|
|
57
|
+
return () => io.disconnect();
|
|
58
|
+
}, [hasMore, loading, failed, rootMargin]);
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", { "data-load-more": "", "data-state": loading ? "loading" : failed ? "failed" : hasMore ? "idle" : "end", className: cn("relative flex min-h-14 items-center justify-center py-6", className), ...props, children: [
|
|
60
|
+
/* @__PURE__ */ jsx2("div", { ref: sentinel, "aria-hidden": true, className: "pointer-events-none absolute inset-x-0 top-0 h-px" }),
|
|
61
|
+
loading ? /* @__PURE__ */ jsx2(Spinner, { label: loadingLabel, size: "md" }) : hasMore ? /* @__PURE__ */ jsx2(Button, { type: "button", variant: "secondary", size: "md", onClick: () => onLoadMore(), children: failed ? retryLabel ?? label : label }) : endLabel ? /* @__PURE__ */ jsx2("p", { className: "m-0 text-sm text-fg-secondary", children: endLabel }) : null
|
|
62
|
+
] });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/media-grid/shorts-shelf.tsx
|
|
66
|
+
import * as React2 from "react";
|
|
67
|
+
|
|
68
|
+
// src/block-link.tsx
|
|
69
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
18
70
|
var isExternal = (href) => /^[a-z][a-z0-9+.-]*:/i.test(href);
|
|
19
71
|
function BlockLink({
|
|
20
72
|
href,
|
|
@@ -23,38 +75,38 @@ function BlockLink({
|
|
|
23
75
|
rel,
|
|
24
76
|
...props
|
|
25
77
|
}) {
|
|
26
|
-
if (external) return /* @__PURE__ */
|
|
78
|
+
if (external) return /* @__PURE__ */ jsx3("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
27
79
|
const Comp = Link;
|
|
28
|
-
return /* @__PURE__ */
|
|
80
|
+
return /* @__PURE__ */ jsx3(Comp, { href, ...props });
|
|
29
81
|
}
|
|
30
82
|
|
|
31
83
|
// src/media-grid/shorts-shelf.tsx
|
|
32
|
-
import { jsx as
|
|
33
|
-
var Chevron = ({ flip }) => /* @__PURE__ */
|
|
84
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
85
|
+
var Chevron = ({ flip }) => /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, className: flip ? "rotate-180" : void 0, children: /* @__PURE__ */ jsx4("path", { d: "m9 6 6 6-6 6" }) });
|
|
34
86
|
var ARROW = "hidden h-9 w-9 items-center justify-center rounded-full border border-border-default bg-surface-1 text-fg shadow-sm transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-40 [@media(hover:hover)]:inline-flex";
|
|
35
87
|
function ShortsShelf({ label, title, items, getId, renderItem, seeAll, previousLabel, nextLabel, className, ...props }) {
|
|
36
|
-
const row =
|
|
37
|
-
const [edge, setEdge] =
|
|
38
|
-
const measure =
|
|
88
|
+
const row = React2.useRef(null);
|
|
89
|
+
const [edge, setEdge] = React2.useState({ start: true, end: false });
|
|
90
|
+
const measure = React2.useCallback(() => {
|
|
39
91
|
const el = row.current;
|
|
40
92
|
if (!el) return;
|
|
41
93
|
setEdge({ start: el.scrollLeft <= 2, end: el.scrollLeft + el.clientWidth >= el.scrollWidth - 2 });
|
|
42
94
|
}, []);
|
|
43
|
-
|
|
95
|
+
React2.useEffect(measure, [measure, items.length]);
|
|
44
96
|
const page = (dir) => {
|
|
45
97
|
const el = row.current;
|
|
46
98
|
if (el) el.scrollBy({ left: dir * el.clientWidth * 0.85, behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth" });
|
|
47
99
|
};
|
|
48
|
-
const headingId =
|
|
100
|
+
const headingId = React2.useId();
|
|
49
101
|
if (items.length === 0) return null;
|
|
50
|
-
return /* @__PURE__ */
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
-
/* @__PURE__ */
|
|
53
|
-
seeAll && /* @__PURE__ */
|
|
54
|
-
/* @__PURE__ */
|
|
55
|
-
/* @__PURE__ */
|
|
102
|
+
return /* @__PURE__ */ jsxs2("section", { "aria-labelledby": headingId, "data-shorts-shelf": true, className: cn("min-w-0", className), ...props, children: [
|
|
103
|
+
/* @__PURE__ */ jsxs2("div", { className: "mb-3 flex items-center gap-2", children: [
|
|
104
|
+
/* @__PURE__ */ jsx4("h2", { id: headingId, className: "m-0 mr-auto text-base font-bold text-fg", children: title ?? label }),
|
|
105
|
+
seeAll && /* @__PURE__ */ jsx4(BlockLink, { href: seeAll.href, linkAs: seeAll.linkAs, className: "text-sm font-semibold text-fg-accent hover:underline", children: seeAll.label }),
|
|
106
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "aria-label": previousLabel, disabled: edge.start, onClick: () => page(-1), className: ARROW, children: /* @__PURE__ */ jsx4(Chevron, { flip: true }) }),
|
|
107
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "aria-label": nextLabel, disabled: edge.end, onClick: () => page(1), className: ARROW, children: /* @__PURE__ */ jsx4(Chevron, {}) })
|
|
56
108
|
] }),
|
|
57
|
-
/* @__PURE__ */
|
|
109
|
+
/* @__PURE__ */ jsx4(
|
|
58
110
|
"ul",
|
|
59
111
|
{
|
|
60
112
|
ref: row,
|
|
@@ -62,14 +114,14 @@ function ShortsShelf({ label, title, items, getId, renderItem, seeAll, previousL
|
|
|
62
114
|
tabIndex: 0,
|
|
63
115
|
"aria-labelledby": headingId,
|
|
64
116
|
className: "m-0 flex list-none snap-x snap-mandatory items-stretch gap-3 overflow-x-auto overscroll-x-contain p-0 pb-2 [scrollbar-width:none] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-scrollbar]:hidden",
|
|
65
|
-
children: items.map((item, i) => /* @__PURE__ */
|
|
117
|
+
children: items.map((item, i) => /* @__PURE__ */ jsx4("li", { className: "w-[9.5rem] shrink-0 snap-start sm:w-44", children: renderItem(item, i) }, getId(item)))
|
|
66
118
|
}
|
|
67
119
|
)
|
|
68
120
|
] });
|
|
69
121
|
}
|
|
70
122
|
|
|
71
123
|
// src/media-grid/media-grid.tsx
|
|
72
|
-
import { jsx as
|
|
124
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
73
125
|
var GRID = {
|
|
74
126
|
landscape: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
75
127
|
portrait: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6"
|
|
@@ -81,18 +133,18 @@ function MediaGrid({ items, getId, orientationOf, renderItem, mode = "split", fr
|
|
|
81
133
|
const rest = split ? items.filter((i) => orientationOf(i) !== "portrait") : items;
|
|
82
134
|
const gridFrame = split ? "landscape" : frame;
|
|
83
135
|
const state = (item, aspect) => ({ aspect, layout: row ? "row" : "stack", mismatch: orientationOf(item) !== aspect });
|
|
84
|
-
return /* @__PURE__ */
|
|
85
|
-
verticals.length > 0 && /* @__PURE__ */
|
|
86
|
-
rest.length > 0 && /* @__PURE__ */
|
|
136
|
+
return /* @__PURE__ */ jsxs3("div", { "data-media-grid": mode, className: cn("flex min-w-0 flex-col gap-8", className), ...props, children: [
|
|
137
|
+
verticals.length > 0 && /* @__PURE__ */ jsx5(ShortsShelf, { ...shelf, items: verticals, getId, renderItem: (item) => renderItem(item, { ...state(item, "portrait"), layout: "stack" }) }),
|
|
138
|
+
rest.length > 0 && /* @__PURE__ */ jsx5("ul", { "data-grid-frame": gridFrame, className: cn("m-0 grid list-none auto-rows-fr gap-4 p-0", row ? "grid-cols-1" : GRID[gridFrame]), children: rest.map((item) => /* @__PURE__ */ jsx5("li", { className: "min-w-0", children: renderItem(item, state(item, gridFrame)) }, getId(item))) })
|
|
87
139
|
] });
|
|
88
140
|
}
|
|
89
141
|
|
|
90
142
|
// src/media-grid/video-card.tsx
|
|
91
|
-
import * as
|
|
143
|
+
import * as React3 from "react";
|
|
92
144
|
|
|
93
145
|
// src/card/card.tsx
|
|
94
146
|
import { Slot } from "radix-ui";
|
|
95
|
-
import { tv } from "tailwind-variants";
|
|
147
|
+
import { tv as tv2 } from "tailwind-variants";
|
|
96
148
|
|
|
97
149
|
// src/card/recipe.ts
|
|
98
150
|
var cardRecipe = defineRecipe({
|
|
@@ -120,13 +172,13 @@ var cardRecipe = defineRecipe({
|
|
|
120
172
|
});
|
|
121
173
|
|
|
122
174
|
// src/card/card.tsx
|
|
123
|
-
import { jsx as
|
|
124
|
-
var card =
|
|
175
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
176
|
+
var card = tv2(cardRecipe);
|
|
125
177
|
var slots = card();
|
|
126
178
|
function CardRoot({ asChild, reveal, radius, tone, interactive, className, style, ...props }) {
|
|
127
179
|
const Comp = asChild ? Slot.Root : "div";
|
|
128
180
|
const revealStyle = reveal === void 0 ? style : { ...style, "--kz-delay": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` };
|
|
129
|
-
return /* @__PURE__ */
|
|
181
|
+
return /* @__PURE__ */ jsx6(
|
|
130
182
|
Comp,
|
|
131
183
|
{
|
|
132
184
|
"data-reveal": reveal === void 0 ? void 0 : "",
|
|
@@ -139,13 +191,13 @@ function CardRoot({ asChild, reveal, radius, tone, interactive, className, style
|
|
|
139
191
|
}
|
|
140
192
|
var ASPECT = { video: "aspect-video", square: "aspect-square", portrait: "aspect-[3/4]", auto: "" };
|
|
141
193
|
function CardMedia({ aspect = "video", className, ...props }) {
|
|
142
|
-
return /* @__PURE__ */
|
|
194
|
+
return /* @__PURE__ */ jsx6("div", { "data-aspect": aspect, className: slots.media({ className: cn(ASPECT[aspect], className) }), ...props });
|
|
143
195
|
}
|
|
144
196
|
function CardImage({ src, alt = "", fallback, loading = "lazy", className, ...props }) {
|
|
145
197
|
if (!src) {
|
|
146
|
-
return /* @__PURE__ */
|
|
198
|
+
return /* @__PURE__ */ jsx6("div", { "data-fallback": "", "aria-hidden": true, className: slots.fallback({ className }), children: fallback });
|
|
147
199
|
}
|
|
148
|
-
return /* @__PURE__ */
|
|
200
|
+
return /* @__PURE__ */ jsx6("img", { src, alt, loading, decoding: "async", className: slots.image({ className }), ...props });
|
|
149
201
|
}
|
|
150
202
|
var CORNER = {
|
|
151
203
|
"top-left": "left-2.5 top-2.5",
|
|
@@ -154,25 +206,25 @@ var CORNER = {
|
|
|
154
206
|
"bottom-right": "bottom-2.5 right-2.5"
|
|
155
207
|
};
|
|
156
208
|
function CardOverlay({ corner = "top-left", className, ...props }) {
|
|
157
|
-
return /* @__PURE__ */
|
|
209
|
+
return /* @__PURE__ */ jsx6("div", { "data-corner": corner, className: slots.overlay({ className: cn(CORNER[corner], className) }), ...props });
|
|
158
210
|
}
|
|
159
211
|
function CardBody({ padding, className, ...props }) {
|
|
160
|
-
return /* @__PURE__ */
|
|
212
|
+
return /* @__PURE__ */ jsx6("div", { className: card({ padding }).body({ className }), ...props });
|
|
161
213
|
}
|
|
162
214
|
function CardTitle({ as: Tag = "h3", className, ...props }) {
|
|
163
|
-
return /* @__PURE__ */
|
|
215
|
+
return /* @__PURE__ */ jsx6(Tag, { className: slots.title({ className }), ...props });
|
|
164
216
|
}
|
|
165
217
|
function CardDescription({ className, ...props }) {
|
|
166
|
-
return /* @__PURE__ */
|
|
218
|
+
return /* @__PURE__ */ jsx6("p", { className: slots.description({ className }), ...props });
|
|
167
219
|
}
|
|
168
220
|
function CardStat({ label, className, children, ...props }) {
|
|
169
|
-
return /* @__PURE__ */
|
|
170
|
-
/* @__PURE__ */
|
|
171
|
-
/* @__PURE__ */
|
|
221
|
+
return /* @__PURE__ */ jsxs4("div", { className: slots.stat({ className }), ...props, children: [
|
|
222
|
+
/* @__PURE__ */ jsx6("p", { className: slots.statLabel(), children: label }),
|
|
223
|
+
/* @__PURE__ */ jsx6("p", { className: slots.statValue(), children })
|
|
172
224
|
] });
|
|
173
225
|
}
|
|
174
226
|
function CardFooter({ className, ...props }) {
|
|
175
|
-
return /* @__PURE__ */
|
|
227
|
+
return /* @__PURE__ */ jsx6("div", { className: slots.footer({ className }), ...props });
|
|
176
228
|
}
|
|
177
229
|
var Card = {
|
|
178
230
|
Root: CardRoot,
|
|
@@ -186,8 +238,48 @@ var Card = {
|
|
|
186
238
|
Footer: CardFooter
|
|
187
239
|
};
|
|
188
240
|
|
|
241
|
+
// src/media-grid/preview-focus.ts
|
|
242
|
+
var MIN_RATIO = 0.6;
|
|
243
|
+
var ratios = /* @__PURE__ */ new Map();
|
|
244
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
245
|
+
var observer = null;
|
|
246
|
+
var leader = null;
|
|
247
|
+
function elect() {
|
|
248
|
+
let best = null;
|
|
249
|
+
let bestRatio = MIN_RATIO - Number.EPSILON;
|
|
250
|
+
for (const [el, ratio] of ratios) {
|
|
251
|
+
if (ratio > bestRatio) {
|
|
252
|
+
best = el;
|
|
253
|
+
bestRatio = ratio;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (best === leader) return;
|
|
257
|
+
leader = best;
|
|
258
|
+
for (const l of listeners) l();
|
|
259
|
+
}
|
|
260
|
+
function trackVisibility(el) {
|
|
261
|
+
if (typeof IntersectionObserver === "undefined") return () => {
|
|
262
|
+
};
|
|
263
|
+
observer ??= new IntersectionObserver(
|
|
264
|
+
(entries) => {
|
|
265
|
+
for (const e of entries) ratios.set(e.target, e.isIntersecting ? e.intersectionRatio : 0);
|
|
266
|
+
elect();
|
|
267
|
+
},
|
|
268
|
+
{ threshold: [0, 0.25, 0.5, 0.6, 0.75, 1] }
|
|
269
|
+
);
|
|
270
|
+
ratios.set(el, 0);
|
|
271
|
+
observer.observe(el);
|
|
272
|
+
return () => {
|
|
273
|
+
observer?.unobserve(el);
|
|
274
|
+
ratios.delete(el);
|
|
275
|
+
elect();
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
var subscribeLeader = (l) => (listeners.add(l), () => void listeners.delete(l));
|
|
279
|
+
var isLeader = (el) => el !== null && leader === el;
|
|
280
|
+
|
|
189
281
|
// src/media-grid/video-card.tsx
|
|
190
|
-
import { jsx as
|
|
282
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
191
283
|
var FRAME = { landscape: "aspect-video", portrait: "aspect-[9/16]" };
|
|
192
284
|
function VideoCard({
|
|
193
285
|
title,
|
|
@@ -197,6 +289,8 @@ function VideoCard({
|
|
|
197
289
|
layout = "stack",
|
|
198
290
|
poster,
|
|
199
291
|
previewSrc,
|
|
292
|
+
previewDelay = 200,
|
|
293
|
+
posterPriority = "auto",
|
|
200
294
|
fit = "cover",
|
|
201
295
|
duration,
|
|
202
296
|
badges,
|
|
@@ -212,41 +306,63 @@ function VideoCard({
|
|
|
212
306
|
onMouseLeave,
|
|
213
307
|
onFocus,
|
|
214
308
|
onBlur,
|
|
309
|
+
ref,
|
|
215
310
|
...props
|
|
216
311
|
}) {
|
|
217
|
-
const [
|
|
218
|
-
const
|
|
312
|
+
const [node, setNode] = React3.useState(null);
|
|
313
|
+
const setRef = React3.useCallback(
|
|
314
|
+
(el) => {
|
|
315
|
+
setNode(el);
|
|
316
|
+
if (typeof ref === "function") ref(el);
|
|
317
|
+
else if (ref) ref.current = el;
|
|
318
|
+
},
|
|
319
|
+
[ref]
|
|
320
|
+
);
|
|
321
|
+
const canPreview = Boolean(previewSrc) && !blurred;
|
|
322
|
+
const { live, arm, disarm } = usePreviewIntent(node, canPreview, previewDelay);
|
|
219
323
|
const row = layout === "row";
|
|
220
324
|
const tall = aspect === "portrait" && !row;
|
|
221
|
-
return /* @__PURE__ */
|
|
325
|
+
return /* @__PURE__ */ jsx7(
|
|
222
326
|
"article",
|
|
223
327
|
{
|
|
328
|
+
ref: setRef,
|
|
224
329
|
"data-aspect": aspect,
|
|
225
330
|
"data-layout": layout,
|
|
226
331
|
className: cn("group relative h-full min-w-0", className),
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
332
|
+
"data-preview": live ? "on" : void 0,
|
|
333
|
+
onMouseEnter: (e) => (arm("pointer"), onMouseEnter?.(e)),
|
|
334
|
+
onMouseLeave: (e) => (disarm("pointer"), onMouseLeave?.(e)),
|
|
335
|
+
onFocus: (e) => (arm("focus"), onFocus?.(e)),
|
|
336
|
+
onBlur: (e) => (disarm("focus"), onBlur?.(e)),
|
|
231
337
|
...props,
|
|
232
|
-
children: /* @__PURE__ */
|
|
233
|
-
/* @__PURE__ */
|
|
234
|
-
fit === "contain" &&
|
|
235
|
-
/* @__PURE__ */
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
338
|
+
children: /* @__PURE__ */ jsxs5(Card.Root, { interactive: true, tone: "glass", className: cn("h-full w-full max-w-full", row ? "flex-row" : "flex-col"), children: [
|
|
339
|
+
/* @__PURE__ */ jsxs5(Card.Media, { aspect: "auto", className: cn("shrink-0", FRAME[aspect], row && (aspect === "portrait" ? "w-24 sm:w-28" : "w-40 sm:w-56")), children: [
|
|
340
|
+
fit === "contain" && poster && /* @__PURE__ */ jsx7("img", { src: poster, alt: "", "aria-hidden": true, loading: "lazy", className: "absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl" }),
|
|
341
|
+
/* @__PURE__ */ jsx7(
|
|
342
|
+
Card.Image,
|
|
343
|
+
{
|
|
344
|
+
src: poster,
|
|
345
|
+
loading,
|
|
346
|
+
fetchPriority: posterPriority === "auto" ? void 0 : posterPriority,
|
|
347
|
+
fallback,
|
|
348
|
+
className: cn(fit === "contain" && "relative object-contain", blurred && "scale-110 blur-xl")
|
|
349
|
+
}
|
|
350
|
+
),
|
|
351
|
+
live && previewSrc && /* @__PURE__ */ jsx7(PreviewLayer, { src: previewSrc, contain: fit === "contain" }),
|
|
352
|
+
overlay && /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 z-20 flex", children: overlay }),
|
|
353
|
+
badges && /* @__PURE__ */ jsx7(Card.Overlay, { corner: "top-left", className: "theme-dark pointer-events-none flex-wrap", children: badges }),
|
|
354
|
+
duration && /* @__PURE__ */ jsx7(Card.Overlay, { corner: "bottom-right", className: "pointer-events-none", children: /* @__PURE__ */ jsx7("span", { className: "rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media", children: duration }) })
|
|
239
355
|
] }),
|
|
240
|
-
/* @__PURE__ */
|
|
241
|
-
/* @__PURE__ */
|
|
242
|
-
/* @__PURE__ */
|
|
243
|
-
creator && /* @__PURE__ */
|
|
244
|
-
/* @__PURE__ */
|
|
245
|
-
creator.href ? /* @__PURE__ */
|
|
356
|
+
/* @__PURE__ */ jsxs5(Card.Body, { className: "static min-w-0 flex-1 justify-between gap-2 p-3", children: [
|
|
357
|
+
/* @__PURE__ */ jsx7("h3", { className: "m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg", children: /* @__PURE__ */ jsx7(BlockLink, { href, linkAs, className: "line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring", children: title }) }),
|
|
358
|
+
/* @__PURE__ */ jsxs5("div", { className: cn("relative z-10 text-xs text-fg-secondary", tall ? "flex flex-col gap-1" : "flex h-8 items-center gap-2"), children: [
|
|
359
|
+
creator && /* @__PURE__ */ jsxs5("div", { className: "flex h-6 min-w-0 items-center gap-2", children: [
|
|
360
|
+
/* @__PURE__ */ jsx7(Avatar, { src: creator.avatarSrc, defaultAvatar: creator.defaultAvatar, alt: "", fallback: creator.name.charAt(0), size: "xs", className: "shrink-0" }),
|
|
361
|
+
creator.href ? /* @__PURE__ */ jsx7(BlockLink, { href: creator.href, linkAs, className: "min-w-0 truncate hover:text-fg", children: creator.name }) : /* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: creator.name })
|
|
246
362
|
] }),
|
|
247
|
-
(meta || action) && /* @__PURE__ */
|
|
248
|
-
meta && /* @__PURE__ */
|
|
249
|
-
action && /* @__PURE__ */
|
|
363
|
+
(meta || action) && /* @__PURE__ */ jsxs5("div", { className: cn("flex items-center gap-2", tall ? "h-7 justify-between" : "ml-auto shrink-0"), children: [
|
|
364
|
+
meta && /* @__PURE__ */ jsx7("span", { className: "shrink-0 font-mono text-[11px] text-fg-muted", children: meta }),
|
|
365
|
+
action && /* @__PURE__ */ jsx7("span", { className: "shrink-0", children: action })
|
|
250
366
|
] })
|
|
251
367
|
] })
|
|
252
368
|
] })
|
|
@@ -254,9 +370,140 @@ function VideoCard({
|
|
|
254
370
|
}
|
|
255
371
|
);
|
|
256
372
|
}
|
|
373
|
+
function PreviewLayer({ src, contain }) {
|
|
374
|
+
const [ready, setReady] = React3.useState(false);
|
|
375
|
+
return /* @__PURE__ */ jsx7(
|
|
376
|
+
"img",
|
|
377
|
+
{
|
|
378
|
+
src,
|
|
379
|
+
alt: "",
|
|
380
|
+
"aria-hidden": true,
|
|
381
|
+
decoding: "async",
|
|
382
|
+
"data-preview-layer": "",
|
|
383
|
+
"data-ready": ready ? "" : void 0,
|
|
384
|
+
onLoad: () => setReady(true),
|
|
385
|
+
className: cn("pointer-events-none absolute inset-0 h-full w-full opacity-0 transition-opacity duration-300 data-[ready]:opacity-100 motion-reduce:transition-none", contain ? "object-contain" : "object-cover")
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
var matches = (query) => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(query).matches;
|
|
390
|
+
var hoverCapable = () => matches("(hover: hover)");
|
|
391
|
+
var saveData = () => typeof navigator !== "undefined" && navigator.connection?.saveData === true;
|
|
392
|
+
function usePreviewIntent(node, enabled, delay) {
|
|
393
|
+
const [causes, setCauses] = React3.useState(/* @__PURE__ */ new Set());
|
|
394
|
+
const timers = React3.useRef(/* @__PURE__ */ new Map());
|
|
395
|
+
const arm = React3.useCallback(
|
|
396
|
+
(cause) => {
|
|
397
|
+
if (!enabled || saveData()) return;
|
|
398
|
+
if (cause === "pointer" && !hoverCapable()) return;
|
|
399
|
+
clearTimeout(timers.current.get(cause));
|
|
400
|
+
timers.current.set(
|
|
401
|
+
cause,
|
|
402
|
+
setTimeout(() => setCauses((c) => new Set(c).add(cause)), delay)
|
|
403
|
+
);
|
|
404
|
+
},
|
|
405
|
+
[enabled, delay]
|
|
406
|
+
);
|
|
407
|
+
const disarm = React3.useCallback((cause) => {
|
|
408
|
+
clearTimeout(timers.current.get(cause));
|
|
409
|
+
timers.current.delete(cause);
|
|
410
|
+
setCauses((c) => {
|
|
411
|
+
if (!c.has(cause)) return c;
|
|
412
|
+
const next = new Set(c);
|
|
413
|
+
next.delete(cause);
|
|
414
|
+
return next;
|
|
415
|
+
});
|
|
416
|
+
}, []);
|
|
417
|
+
React3.useEffect(() => {
|
|
418
|
+
const pending = timers.current;
|
|
419
|
+
return () => {
|
|
420
|
+
for (const t of pending.values()) clearTimeout(t);
|
|
421
|
+
pending.clear();
|
|
422
|
+
};
|
|
423
|
+
}, []);
|
|
424
|
+
const touch = enabled && !hoverCapable();
|
|
425
|
+
const leading = React3.useSyncExternalStore(
|
|
426
|
+
subscribeLeader,
|
|
427
|
+
() => isLeader(node),
|
|
428
|
+
() => false
|
|
429
|
+
);
|
|
430
|
+
React3.useEffect(() => {
|
|
431
|
+
if (!node || !touch) return;
|
|
432
|
+
return trackVisibility(node);
|
|
433
|
+
}, [node, touch]);
|
|
434
|
+
const [ready, setReady] = React3.useState(false);
|
|
435
|
+
const [wasLeading, setWasLeading] = React3.useState(false);
|
|
436
|
+
if (leading !== wasLeading) {
|
|
437
|
+
setWasLeading(leading);
|
|
438
|
+
if (!leading) setReady(false);
|
|
439
|
+
}
|
|
440
|
+
const wanted = touch && leading && !saveData() && !matches("(prefers-reduced-motion: reduce)");
|
|
441
|
+
React3.useEffect(() => {
|
|
442
|
+
if (!wanted) return;
|
|
443
|
+
const t = setTimeout(() => setReady(true), delay);
|
|
444
|
+
return () => clearTimeout(t);
|
|
445
|
+
}, [wanted, delay]);
|
|
446
|
+
return { live: enabled && (causes.size > 0 || wanted && ready), arm, disarm };
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/skeleton/skeleton.tsx
|
|
450
|
+
import { tv as tv3 } from "tailwind-variants";
|
|
451
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
452
|
+
var skeletonVariants = tv3({
|
|
453
|
+
base: "kz-skeleton block bg-surface-3",
|
|
454
|
+
variants: {
|
|
455
|
+
shape: { text: "h-3 w-full rounded-sm", circle: "aspect-square h-10 rounded-full", rect: "h-24 w-full rounded-lg" }
|
|
456
|
+
},
|
|
457
|
+
defaultVariants: { shape: "text" }
|
|
458
|
+
});
|
|
459
|
+
function Skeleton({ shape, className, ...props }) {
|
|
460
|
+
return /* @__PURE__ */ jsx8("span", { "aria-hidden": true, "data-shape": shape ?? "text", className: skeletonVariants({ shape, className }), ...props });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/media-grid/video-card-skeleton.tsx
|
|
464
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
465
|
+
var FRAME2 = { landscape: "aspect-video", portrait: "aspect-[9/16]" };
|
|
466
|
+
function VideoCardSkeleton({ aspect = "landscape", layout = "stack", className, ...props }) {
|
|
467
|
+
const row = layout === "row";
|
|
468
|
+
const tall = aspect === "portrait" && !row;
|
|
469
|
+
return /* @__PURE__ */ jsx9("div", { "aria-hidden": true, "data-skeleton": "video-card", "data-aspect": aspect, "data-layout": layout, className: cn("h-full min-w-0", className), ...props, children: /* @__PURE__ */ jsxs6(Card.Root, { tone: "glass", className: cn("h-full w-full max-w-full", row ? "flex-row" : "flex-col"), children: [
|
|
470
|
+
/* @__PURE__ */ jsx9(Card.Media, { aspect: "auto", className: cn("shrink-0", FRAME2[aspect], row && (aspect === "portrait" ? "w-24 sm:w-28" : "w-40 sm:w-56")), children: /* @__PURE__ */ jsx9(Skeleton, { shape: "rect", className: "h-full w-full rounded-none" }) }),
|
|
471
|
+
/* @__PURE__ */ jsxs6(Card.Body, { className: "static min-w-0 flex-1 justify-between gap-2 p-3", children: [
|
|
472
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex min-h-[2.5em] flex-col justify-center gap-1.5", children: [
|
|
473
|
+
/* @__PURE__ */ jsx9(Skeleton, { className: "h-3" }),
|
|
474
|
+
/* @__PURE__ */ jsx9(Skeleton, { className: "h-3 w-3/5" })
|
|
475
|
+
] }),
|
|
476
|
+
/* @__PURE__ */ jsxs6("div", { className: cn("flex text-xs", tall ? "flex-col gap-1" : "h-8 items-center gap-2"), children: [
|
|
477
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex h-6 min-w-0 items-center gap-2", children: [
|
|
478
|
+
/* @__PURE__ */ jsx9(Skeleton, { shape: "circle", className: "h-6 w-6 shrink-0" }),
|
|
479
|
+
/* @__PURE__ */ jsx9(Skeleton, { className: "h-2.5 w-20" })
|
|
480
|
+
] }),
|
|
481
|
+
/* @__PURE__ */ jsx9("div", { className: cn("flex items-center", tall ? "h-7" : "ml-auto"), children: /* @__PURE__ */ jsx9(Skeleton, { className: "h-2.5 w-14" }) })
|
|
482
|
+
] })
|
|
483
|
+
] })
|
|
484
|
+
] }) });
|
|
485
|
+
}
|
|
486
|
+
var GRID2 = {
|
|
487
|
+
landscape: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
488
|
+
portrait: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6"
|
|
489
|
+
};
|
|
490
|
+
function MediaGridSkeleton({ label, count = 8, shelfCount = 0, layout = "grid", frame = "landscape", className, ...props }) {
|
|
491
|
+
const row = layout === "list";
|
|
492
|
+
return /* @__PURE__ */ jsxs6("div", { role: "status", "aria-busy": "true", "data-media-grid-skeleton": "", className: cn("flex min-w-0 flex-col gap-8", className), ...props, children: [
|
|
493
|
+
/* @__PURE__ */ jsx9("span", { className: "sr-only", children: label }),
|
|
494
|
+
shelfCount > 0 && /* @__PURE__ */ jsxs6("div", { "aria-hidden": true, className: "min-w-0", children: [
|
|
495
|
+
/* @__PURE__ */ jsx9(Skeleton, { className: "mb-3 h-4 w-24" }),
|
|
496
|
+
/* @__PURE__ */ jsx9("ul", { className: "m-0 flex list-none items-stretch gap-3 overflow-hidden p-0", children: Array.from({ length: shelfCount }, (_, i) => /* @__PURE__ */ jsx9("li", { className: "w-[9.5rem] shrink-0 sm:w-44", children: /* @__PURE__ */ jsx9(VideoCardSkeleton, { aspect: "portrait" }) }, i)) })
|
|
497
|
+
] }),
|
|
498
|
+
/* @__PURE__ */ jsx9("ul", { "aria-hidden": true, className: cn("m-0 grid list-none auto-rows-fr gap-4 p-0", row ? "grid-cols-1" : GRID2[frame]), children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx9("li", { className: "min-w-0", children: /* @__PURE__ */ jsx9(VideoCardSkeleton, { aspect: frame, layout: row ? "row" : "stack" }) }, i)) })
|
|
499
|
+
] });
|
|
500
|
+
}
|
|
257
501
|
export {
|
|
502
|
+
LoadMore,
|
|
258
503
|
MediaGrid,
|
|
504
|
+
MediaGridSkeleton,
|
|
259
505
|
ShortsShelf,
|
|
260
|
-
VideoCard
|
|
506
|
+
VideoCard,
|
|
507
|
+
VideoCardSkeleton
|
|
261
508
|
};
|
|
262
509
|
//# sourceMappingURL=media-grid.js.map
|