@openrails/contentkit-ui 0.98.4 → 0.98.6

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/README.md CHANGED
@@ -319,17 +319,24 @@ Plain-text entities sit directly below the cover, followed by other metadata.
319
319
  metadata={{ languages: false, traits: ["colored"], duration: false }} />
320
320
  ```
321
321
 
322
- Set `grid={{ minCardWidth: 240, mobileColumns: 2, maxColumns: 10 }}` for covers in a fluid
323
- grid: two columns on small screens, then as many columns as the available
324
- width supports. This is supported by card grids, daily releases, Popular and
325
- `ContentRail` previews; an unconfigured rail remains horizontal. `maxColumns`
326
- is optional: omit it for no desktop column ceiling. Other apps keep their
327
- existing layout by default.
328
-
329
- `minCardWidth` also accepts a CSS length. For example,
330
- `grid={{ minCardWidth: "clamp(240px, calc((100% - 9rem) / 10), 360px)" }}`
331
- keeps the early narrow-screen columns, grows covers toward 360px, and then
332
- adds columns on ultrawide displays without a ceiling.
322
+ Card grids use **width-driven tiling**: preserve roughly the same apparent
323
+ card size as the container grows, adding or removing columns to use the
324
+ available space. The application supplies its card-width target; ContentKit
325
+ UI derives the column count. Cards may grow slightly to fill each row.
326
+
327
+ For example, `grid={{ minCardWidth: 280, mobileColumns: 2 }}` keeps two columns
328
+ on small screens and a stable 280 CSS-pixel minimum on desktop, with no column
329
+ ceiling. This shared behavior applies to card grids, daily releases, Popular
330
+ and `ContentRail` grid previews; an unconfigured rail remains horizontal.
331
+
332
+ Use a stable CSS-pixel width for ordinary listing cards. `maxColumns` is an
333
+ explicit opt-in for surfaces that intentionally cap their columns.
334
+ `minCardWidth` also accepts CSS lengths for application-specific layouts.
335
+
336
+ Custom page-thumbnail or media grids can use the same primitive: call
337
+ `cardGridLayout({ minCardWidth: 280, mobileColumns: 2 })` and apply its
338
+ `className` and `style` to a `ContentKitUiRoot`. This keeps their track widths,
339
+ gaps and responsive behavior identical to content-card lists.
333
340
 
334
341
  `ContentGrid` and `ContentListing` take `locked`: `show` (default) marks the
335
342
  cards the reader doesn't open, `hide` leaves them out, and `collapse` lists
@@ -1,5 +1,5 @@
1
1
  export { ContentCard, OwnerChip, PostCard, lockLabel, type CardMetadata, type ContentCardProps, type PostCardProps } from './card.js';
2
- export { CardGrid, ContentGrid, ContentHistory, ContentRail, SearchResults, type CardGridLayout, type CardListProps, type ContentRailProps, type LockedCards } from './grid.js';
2
+ export { cardGridLayout, CardGrid, ContentGrid, ContentHistory, ContentRail, SearchResults, type CardGridLayout, type CardListProps, type ContentRailProps, type LockedCards } from './grid.js';
3
3
  export { DailyReleases, type DailyReleasesProps } from './daily-releases.js';
4
4
  export { PopularContentGrid, type PopularContentGridProps } from './popular.js';
5
5
  export { SearchBox, type SearchBoxProps } from './search.js';
@@ -5,14 +5,14 @@ import { ContentKitContext as r } from "../../react/context.js";
5
5
  import { Input as i } from "../../ui/input.js";
6
6
  import { useRecentSearches as a, useTypeahead as o } from "../../react/discovery.js";
7
7
  import { labelOf as s } from "../groups/parts.js";
8
- import { useContext as c, useEffect as ee, useId as te, useLayoutEffect as l, useMemo as u, useRef as d, useState as f } from "react";
8
+ import { useContext as c, useEffect as l, useId as ee, useLayoutEffect as u, useMemo as te, useRef as d, useState as f } from "react";
9
9
  import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
10
10
  import { cn as g } from "cn";
11
11
  import { Cancel01Icon as _, Clock01Icon as v, File01Icon as y, Folder01Icon as b, Image01Icon as x, Search01Icon as S, TagsIcon as C, UserIcon as w } from "@hugeicons/core-free-icons";
12
12
  import { HugeiconsIcon as T } from "@hugeicons/react";
13
- import { createPortal as E } from "react-dom";
13
+ import { createPortal as ne } from "react-dom";
14
14
  //#region src/components/content/search.tsx
15
- var D = {
15
+ var E = {
16
16
  artist: {
17
17
  icon: w,
18
18
  color: "text-blue-500 dark:text-blue-400"
@@ -46,13 +46,13 @@ var D = {
46
46
  color: "text-orange-500 dark:text-orange-400"
47
47
  }
48
48
  };
49
- function O(e, t, n, r) {
49
+ function D(e, t, n, r) {
50
50
  let [i, a] = f({
51
51
  top: 0,
52
52
  left: 0,
53
53
  width: 0
54
54
  });
55
- return l(() => {
55
+ return u(() => {
56
56
  if (!e || !t || !n.current) return;
57
57
  let i = r.current ?? n.current, o = n.current.ownerDocument.defaultView;
58
58
  if (!o) return;
@@ -76,8 +76,8 @@ function O(e, t, n, r) {
76
76
  r
77
77
  ]), i;
78
78
  }
79
- function k({ kind: e }) {
80
- let t = D[e];
79
+ function O({ kind: e }) {
80
+ let t = E[e];
81
81
  return /* @__PURE__ */ m(T, {
82
82
  icon: t?.icon ?? S,
83
83
  strokeWidth: 2,
@@ -86,97 +86,89 @@ function k({ kind: e }) {
86
86
  "aria-hidden": !0
87
87
  });
88
88
  }
89
- function ne({ value: e, formatter: t }) {
90
- return !e || Number.isNaN(Date.parse(e)) ? null : /* @__PURE__ */ m("time", {
91
- dateTime: e,
92
- className: "shrink-0 text-xs text-muted-foreground",
93
- children: t.format(new Date(e))
94
- });
95
- }
96
- function A(l) {
97
- let { t: y, error: b, language: x } = t(), C = te(), w = c(r)?.navigate, [D, A] = f(l.defaultValue ?? ""), [j, M] = f(!1), [N, P] = f(-1), F = d(null), I = d(null), L = d(null), R = l.presentation === "header", z = O(j, R, F, L), { top: B } = z, V = u(() => new Intl.DateTimeFormat(x, { dateStyle: "short" }), [x]), H = !D.trim(), U = o(D, {
98
- kind: l.kind,
99
- entity_kinds: l.groupKinds,
100
- client: l.client
101
- }), W = a({
102
- enabled: l.recent !== !1 && j && H,
103
- client: l.client
104
- }), re = u(() => H ? W.searches.map((e) => ({
89
+ function k(u) {
90
+ let { t: y, error: b } = t(), x = ee(), C = c(r)?.navigate, [w, E] = f(u.defaultValue ?? ""), [k, A] = f(!1), [j, M] = f(-1), N = d(null), P = d(null), F = d(null), I = u.presentation === "header", L = D(k, I, N, F), { top: R } = L, z = !w.trim(), B = o(w, {
91
+ kind: u.kind,
92
+ entity_kinds: u.groupKinds,
93
+ client: u.client
94
+ }), V = a({
95
+ enabled: u.recent !== !1 && k && z,
96
+ client: u.client
97
+ }), H = te(() => z ? V.searches.map((e) => ({
105
98
  type: "recent",
106
- query: e.query,
107
- searchedAt: e.searched_at
108
- })) : [...U.contents.map((e) => ({
99
+ query: e.query
100
+ })) : [...B.contents.map((e) => ({
109
101
  type: "content",
110
102
  card: e
111
- })), ...U.entities.map((e) => ({
103
+ })), ...B.entities.map((e) => ({
112
104
  type: "group",
113
105
  group: e
114
106
  }))], [
115
- H,
116
- W.searches,
117
- U.contents,
118
- U.entities
119
- ]), G = H || U.query === D.trim(), K = G ? re : [], q = K[N], ie = H ? W.loading : !G || U.loading, J = H && l.recent !== !1, ae = H ? !R && J && !W.error ? "contents.noRecentSearches" : "contents.searchHint" : "contents.noResults";
120
- ee(() => {
121
- if (!j) return;
107
+ z,
108
+ V.searches,
109
+ B.contents,
110
+ B.entities
111
+ ]), U = z || B.query === w.trim(), W = U ? H : [], G = W[j], K = z ? V.loading : !U || B.loading, q = z && u.recent !== !1, J = z ? !I && q && !V.error ? "contents.noRecentSearches" : "contents.searchHint" : "contents.noResults";
112
+ l(() => {
113
+ if (!k) return;
122
114
  let e = (e) => {
123
- !F.current?.contains(e.target) && !I.current?.contains(e.target) && M(!1);
115
+ !N.current?.contains(e.target) && !P.current?.contains(e.target) && A(!1);
124
116
  };
125
117
  return document.addEventListener("pointerdown", e), () => document.removeEventListener("pointerdown", e);
126
- }, [j]);
118
+ }, [k]);
127
119
  let Y = () => {
128
- M(!0);
120
+ A(!0);
129
121
  }, X = (e) => {
130
- M(!1), e && l.onSearch(e);
122
+ A(!1), e && u.onSearch(e);
131
123
  }, Z = (e) => {
132
- if (e.type === "recent") return A(e.query), X(e.query);
133
- let t = l.href ? l.href(e.type === "content" ? e.card : e.group) : e.type === "content" ? e.card.path : e.group.path;
134
- M(!1), t && (w ? w(t) : location.assign(t));
124
+ if (e.type === "recent") return E(e.query), X(e.query);
125
+ let t = u.href ? u.href(e.type === "content" ? e.card : e.group) : e.type === "content" ? e.card.path : e.group.path;
126
+ A(!1), t && (C ? C(t) : location.assign(t));
135
127
  }, Q = (e) => {
136
- e.key === "Escape" && (e.preventDefault(), L.current?.focus(), M(!1), P(-1));
128
+ e.key === "Escape" && (e.preventDefault(), F.current?.focus(), A(!1), M(-1));
137
129
  }, $ = /* @__PURE__ */ h(p, { children: [
138
- J && /* @__PURE__ */ h("div", {
139
- className: g("flex items-center justify-between gap-2 text-muted-foreground", R ? "mb-4 text-base font-semibold" : "px-2 py-1 text-xs"),
130
+ q && /* @__PURE__ */ h("div", {
131
+ className: g("flex items-center justify-between gap-2 text-muted-foreground", I ? "mb-4 text-base font-semibold" : "px-2 py-1 text-xs"),
140
132
  children: [/* @__PURE__ */ h("span", {
141
- id: `${C}-recent`,
133
+ id: `${x}-recent`,
142
134
  className: "flex items-center gap-2",
143
- children: [R && /* @__PURE__ */ m(T, {
135
+ children: [I && /* @__PURE__ */ m(T, {
144
136
  icon: v,
145
137
  strokeWidth: 2,
146
138
  className: "size-5",
147
139
  "aria-hidden": !0
148
140
  }), y("contents.recentSearches")]
149
- }), K.length > 0 && /* @__PURE__ */ m("button", {
141
+ }), W.length > 0 && /* @__PURE__ */ m("button", {
150
142
  type: "button",
151
143
  className: "rounded px-1 hover:text-foreground",
152
144
  onMouseDown: (e) => {
153
145
  e.preventDefault();
154
146
  },
155
- onClick: () => void W.clear(),
156
- children: y(R ? "contents.clearAllRecent" : "contents.clearRecent")
147
+ onClick: () => void V.clear(),
148
+ children: y(I ? "contents.clearAllRecent" : "contents.clearRecent")
157
149
  })]
158
150
  }),
159
151
  /* @__PURE__ */ m("ul", {
160
- id: `${C}-list`,
152
+ id: `${x}-list`,
161
153
  role: "listbox",
162
- "aria-label": y(H ? "contents.recentSearches" : "contents.suggestions"),
163
- className: g("grid", R && "gap-2"),
164
- children: K.map((t, n) => /* @__PURE__ */ m("li", {
165
- id: `${C}-${n}`,
154
+ "aria-label": y(z ? "contents.recentSearches" : "contents.suggestions"),
155
+ className: g("grid", I && "gap-2"),
156
+ children: W.map((t, n) => /* @__PURE__ */ m("li", {
157
+ id: `${x}-${n}`,
166
158
  role: "option",
167
- "aria-selected": n === N,
159
+ "aria-selected": n === j,
168
160
  "data-ckui": "suggestion",
169
161
  "data-type": t.type,
170
- className: g("flex cursor-pointer items-center", R ? t.type === "recent" ? "gap-2 rounded-md p-3 text-base hover:bg-foreground/10" : "gap-3 rounded-md px-4 py-1 text-base font-medium hover:bg-foreground/10" : "gap-2 px-2 py-1.5", n === N && "bg-accent text-accent-foreground"),
171
- onMouseEnter: () => P(n),
162
+ className: g("flex cursor-pointer items-center", I ? t.type === "recent" ? "gap-2 rounded-md p-3 text-base hover:bg-foreground/10" : "gap-3 rounded-md px-4 py-1 text-base font-medium hover:bg-foreground/10" : "gap-2 px-2 py-1.5", n === j && "bg-accent text-accent-foreground"),
163
+ onMouseEnter: () => M(n),
172
164
  onMouseDown: (e) => {
173
165
  e.preventDefault(), Z(t);
174
166
  },
175
- children: R && t.type !== "recent" ? /* @__PURE__ */ h(p, { children: [
176
- /* @__PURE__ */ m(k, { kind: t.type === "content" ? t.card.kind : t.group.kind }),
167
+ children: I && t.type !== "recent" ? /* @__PURE__ */ h(p, { children: [
168
+ /* @__PURE__ */ m(O, { kind: t.type === "content" ? t.card.kind : t.group.kind }),
177
169
  /* @__PURE__ */ m("span", {
178
170
  className: "sr-only",
179
- children: s(l.labels, t.type === "content" ? t.card.kind : t.group.kind)
171
+ children: s(u.labels, t.type === "content" ? t.card.kind : t.group.kind)
180
172
  }),
181
173
  /* @__PURE__ */ m("span", {
182
174
  className: "min-w-0 flex-1 truncate",
@@ -198,10 +190,10 @@ function A(l) {
198
190
  children: t.group.name || t.group.slug
199
191
  }), /* @__PURE__ */ m("span", {
200
192
  className: "text-xs text-muted-foreground",
201
- children: s(l.labels, t.group.kind)
193
+ children: s(u.labels, t.group.kind)
202
194
  })] }) : /* @__PURE__ */ h(p, { children: [
203
195
  /* @__PURE__ */ m(T, {
204
- icon: R ? S : v,
196
+ icon: I ? S : v,
205
197
  strokeWidth: 2,
206
198
  className: "size-4 shrink-0 text-muted-foreground",
207
199
  "aria-hidden": !0
@@ -210,10 +202,6 @@ function A(l) {
210
202
  className: "min-w-0 flex-1 truncate",
211
203
  children: t.query
212
204
  }),
213
- R && z.width >= 320 && /* @__PURE__ */ m(ne, {
214
- value: t.searchedAt,
215
- formatter: V
216
- }),
217
205
  /* @__PURE__ */ m("button", {
218
206
  type: "button",
219
207
  className: "rounded p-0.5 text-muted-foreground hover:text-foreground",
@@ -221,7 +209,7 @@ function A(l) {
221
209
  onMouseDown: (e) => {
222
210
  e.preventDefault(), e.stopPropagation();
223
211
  },
224
- onClick: () => void W.clear(t.query),
212
+ onClick: () => void V.clear(t.query),
225
213
  children: /* @__PURE__ */ m(T, {
226
214
  icon: _,
227
215
  strokeWidth: 2,
@@ -232,48 +220,48 @@ function A(l) {
232
220
  ] })
233
221
  }, t.type === "content" ? `c:${t.card.id}` : t.type === "group" ? `g:${t.group.id}` : `r:${t.query}`))
234
222
  }),
235
- ie ? /* @__PURE__ */ m("div", {
223
+ K ? /* @__PURE__ */ m("div", {
236
224
  role: "status",
237
- className: g("text-muted-foreground", R ? "flex justify-center py-4" : "px-3 py-2"),
238
- children: R ? /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("span", {
225
+ className: g("text-muted-foreground", I ? "flex justify-center py-4" : "px-3 py-2"),
226
+ children: I ? /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("span", {
239
227
  className: "size-6 animate-spin rounded-full border-2 border-muted border-t-foreground motion-reduce:animate-none",
240
228
  "aria-hidden": !0
241
229
  }), /* @__PURE__ */ m("span", {
242
230
  className: "sr-only",
243
231
  children: y("contents.loading")
244
232
  })] }) : y("contents.loading")
245
- }) : !H && U.error ? /* @__PURE__ */ m("p", {
233
+ }) : !z && B.error ? /* @__PURE__ */ m("p", {
246
234
  role: "alert",
247
- className: g("px-3 py-2 text-destructive", R && "text-center"),
248
- children: b(U.error)
249
- }) : K.length === 0 && /* @__PURE__ */ h("div", {
235
+ className: g("px-3 py-2 text-destructive", I && "text-center"),
236
+ children: b(B.error)
237
+ }) : W.length === 0 && /* @__PURE__ */ h("div", {
250
238
  role: "status",
251
- className: g("text-muted-foreground", R ? "flex flex-col items-center gap-2 py-8 text-center" : "px-3 py-2"),
252
- children: [R && /* @__PURE__ */ m(T, {
239
+ className: g("text-muted-foreground", I ? "flex flex-col items-center gap-2 py-8 text-center" : "px-3 py-2"),
240
+ children: [I && /* @__PURE__ */ m(T, {
253
241
  icon: S,
254
242
  strokeWidth: 2,
255
243
  className: "size-8",
256
244
  "aria-hidden": !0
257
- }), /* @__PURE__ */ m("p", { children: y(ae, { q: D.trim() }) })]
245
+ }), /* @__PURE__ */ m("p", { children: y(J, { q: w.trim() }) })]
258
246
  })
259
247
  ] });
260
248
  return /* @__PURE__ */ h(n, {
261
- ref: F,
262
- appearance: l.appearance,
263
- className: g("relative text-sm", l.className),
249
+ ref: N,
250
+ appearance: u.appearance,
251
+ className: g("relative text-sm", u.className),
264
252
  "data-ckui": "search-box",
265
253
  onBlur: (e) => {
266
- !e.currentTarget.contains(e.relatedTarget) && !I.current?.contains(e.relatedTarget) && M(!1);
254
+ !e.currentTarget.contains(e.relatedTarget) && !P.current?.contains(e.relatedTarget) && A(!1);
267
255
  },
268
256
  children: [/* @__PURE__ */ h("form", {
269
257
  role: "search",
270
258
  className: "relative",
271
259
  onSubmit: (e) => {
272
- if (e.preventDefault(), j && q) return Z(q);
273
- X(D.trim());
260
+ if (e.preventDefault(), k && G) return Z(G);
261
+ X(w.trim());
274
262
  },
275
263
  children: [
276
- R ? /* @__PURE__ */ m("button", {
264
+ I ? /* @__PURE__ */ m("button", {
277
265
  type: "submit",
278
266
  className: "absolute top-1/2 left-2.5 -translate-y-1/2 rounded text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring",
279
267
  "aria-label": y("contents.search"),
@@ -290,38 +278,38 @@ function A(l) {
290
278
  "aria-hidden": !0
291
279
  }),
292
280
  /* @__PURE__ */ m(i, {
293
- ref: L,
294
- type: R ? "text" : "search",
281
+ ref: F,
282
+ type: I ? "text" : "search",
295
283
  role: "combobox",
296
284
  "aria-label": y("contents.search"),
297
- "aria-expanded": j,
298
- "aria-controls": `${C}-list`,
299
- "aria-activedescendant": j && q ? `${C}-${N}` : void 0,
285
+ "aria-expanded": k,
286
+ "aria-controls": `${x}-list`,
287
+ "aria-activedescendant": k && G ? `${x}-${j}` : void 0,
300
288
  "aria-autocomplete": "list",
301
289
  autoComplete: "off",
302
- className: g("h-9 ps-8", R && "rounded-full border-border/50 bg-foreground/10 pe-9 text-base shadow-none md:text-base"),
303
- value: D,
304
- placeholder: l.placeholder ?? y("contents.searchPlaceholder"),
290
+ className: g("h-9 ps-8", I && "rounded-full border-border/50 bg-foreground/10 pe-9 text-base shadow-none md:text-base"),
291
+ value: w,
292
+ placeholder: u.placeholder ?? y("contents.searchPlaceholder"),
305
293
  onChange: (e) => {
306
- A(e.target.value), M(!0), P(-1);
294
+ E(e.target.value), A(!0), M(-1);
307
295
  },
308
296
  onFocus: Y,
309
297
  onClick: Y,
310
298
  onKeyDown: (e) => {
311
299
  if (e.key === "Escape") {
312
- e.preventDefault(), M(!1), P(-1);
300
+ e.preventDefault(), A(!1), M(-1);
313
301
  return;
314
302
  }
315
- e.key === "ArrowDown" ? (e.preventDefault(), Y(), P((e) => j ? Math.min(K.length - 1, e + 1) : 0)) : e.key === "ArrowUp" && j && (e.preventDefault(), P((e) => Math.max(-1, e - 1)));
303
+ e.key === "ArrowDown" ? (e.preventDefault(), Y(), M((e) => k ? Math.min(W.length - 1, e + 1) : 0)) : e.key === "ArrowUp" && k && (e.preventDefault(), M((e) => Math.max(-1, e - 1)));
316
304
  }
317
305
  }),
318
- R && (D || j) && /* @__PURE__ */ m("button", {
306
+ I && (w || k) && /* @__PURE__ */ m("button", {
319
307
  type: "button",
320
308
  className: "absolute top-1/2 right-2.5 -translate-y-1/2 rounded p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring",
321
- "aria-label": y(D ? "contents.clearSearch" : "common.close"),
309
+ "aria-label": y(w ? "contents.clearSearch" : "common.close"),
322
310
  onMouseDown: (e) => e.preventDefault(),
323
311
  onClick: () => {
324
- L.current?.focus(), P(-1), D ? (A(""), M(!0)) : M(!1);
312
+ F.current?.focus(), M(-1), w ? (E(""), A(!0)) : A(!1);
325
313
  },
326
314
  children: /* @__PURE__ */ m(T, {
327
315
  icon: _,
@@ -331,20 +319,20 @@ function A(l) {
331
319
  })
332
320
  })
333
321
  ]
334
- }), j && (R ? E(/* @__PURE__ */ h(n, {
335
- appearance: l.appearance,
322
+ }), k && (I ? ne(/* @__PURE__ */ h(n, {
323
+ appearance: u.appearance,
336
324
  className: "fixed inset-x-0 bottom-0 z-[70] text-sm",
337
- style: { top: B },
325
+ style: { top: R },
338
326
  "data-ckui": "search-layer",
339
327
  children: [/* @__PURE__ */ m("div", {
340
328
  className: "absolute inset-0 bg-black/30 backdrop-blur-sm",
341
329
  "data-ckui": "search-backdrop",
342
330
  "aria-hidden": !0
343
331
  }), /* @__PURE__ */ m("div", {
344
- ref: I,
332
+ ref: P,
345
333
  style: {
346
- width: z.width,
347
- marginLeft: z.left
334
+ width: L.width,
335
+ marginLeft: L.left
348
336
  },
349
337
  className: "relative origin-top animate-[search-expand_300ms_ease-out] rounded-lg border border-border bg-background text-foreground shadow-lg transition-none motion-reduce:animate-none",
350
338
  "data-ckui": "search-panel",
@@ -353,13 +341,13 @@ function A(l) {
353
341
  className: "w-full px-3 pt-3",
354
342
  children: /* @__PURE__ */ m("div", {
355
343
  className: "[--search-max-height:70vh] overflow-y-auto pb-7 md:[--search-max-height:60vh]",
356
- style: { maxHeight: `min(var(--search-max-height), calc(100dvh - ${B}px - 1.875rem))` },
344
+ style: { maxHeight: `min(var(--search-max-height), calc(100dvh - ${R}px - 1.875rem))` },
357
345
  children: /* @__PURE__ */ m("div", { children: $ })
358
346
  })
359
347
  })
360
348
  })]
361
349
  }), document.body) : /* @__PURE__ */ m("div", {
362
- ref: I,
350
+ ref: P,
363
351
  className: "absolute top-full z-20 mt-1 grid max-h-96 w-full overflow-auto rounded-md border border-border bg-popover py-1 text-popover-foreground shadow-md",
364
352
  "data-ckui": "search-panel",
365
353
  onKeyDown: Q,
@@ -368,6 +356,6 @@ function A(l) {
368
356
  });
369
357
  }
370
358
  //#endregion
371
- export { A as SearchBox };
359
+ export { k as SearchBox };
372
360
 
373
361
  //# sourceMappingURL=search.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","names":[],"sources":["../../../src/components/content/search.tsx"],"sourcesContent":["import { Cancel01Icon, Clock01Icon, File01Icon, Folder01Icon, Image01Icon, Search01Icon, TagsIcon, UserIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon, type IconSvgElement } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, type RefObject, type KeyboardEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Card, GroupCard } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext } from \"../../react/context.js\";\nimport { useRecentSearches, useTypeahead } from \"../../react/discovery.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Input } from \"#ckui/ui/input\";\nimport { RenditionImg } from \"../rendition-img.js\";\nimport { labelOf, type Labels } from \"../groups/parts.js\";\n\nexport interface SearchBoxProps {\n /** Submits the text: the host shows its search page. */\n onSearch: (q: string) => void;\n /** Suggest contents of this kind only. */\n kind?: string;\n /** The group kinds suggested; every kind with a page by default. */\n groupKinds?: readonly string[];\n defaultValue?: string;\n placeholder?: string;\n /** A suggestion's link; default its canonical path. */\n href?: (item: Card | GroupCard) => string | undefined;\n labels?: Labels;\n /** The reader's recent searches while the box is empty. Default true. */\n recent?: boolean;\n /** A portal dropdown anchored to the header field; default stays inline. */\n presentation?: \"inline\" | \"header\";\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\ntype Suggestion = { type: \"content\"; card: Card } | { type: \"group\"; group: GroupCard } | { type: \"recent\"; query: string; searchedAt?: string };\n\nconst TYPE_ICONS: Record<string, { icon: IconSvgElement; color: string }> = {\n artist: { icon: UserIcon, color: \"text-blue-500 dark:text-blue-400\" },\n series: { icon: Folder01Icon, color: \"text-yellow-600 dark:text-yellow-400\" },\n gallery: { icon: Image01Icon, color: \"text-green-600 dark:text-green-400\" },\n post: { icon: File01Icon, color: \"text-purple-500 dark:text-purple-400\" },\n blog: { icon: File01Icon, color: \"text-purple-500 dark:text-purple-400\" },\n poll: { icon: File01Icon, color: \"text-purple-500 dark:text-purple-400\" },\n character: { icon: UserIcon, color: \"text-purple-500 dark:text-purple-400\" },\n tag: { icon: TagsIcon, color: \"text-orange-500 dark:text-orange-400\" },\n};\n\nfunction useHeaderAnchor(open: boolean, enabled: boolean, root: RefObject<HTMLDivElement | null>, input: RefObject<HTMLInputElement | null>) {\n const [position, setPosition] = useState({ top: 0, left: 0, width: 0 });\n useLayoutEffect(() => {\n if (!open || !enabled || !root.current) return;\n const anchor = input.current ?? root.current;\n const view = root.current.ownerDocument.defaultView;\n if (!view) return;\n const measure = () => {\n const rect = anchor.getBoundingClientRect();\n setPosition({ top: Math.max(0, Math.min(view.innerHeight, rect.bottom + 4)), left: rect.left, width: rect.width });\n };\n measure();\n const observer = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(measure);\n observer?.observe(anchor);\n view.addEventListener(\"resize\", measure);\n view.addEventListener(\"scroll\", measure, true);\n view.visualViewport?.addEventListener(\"resize\", measure);\n view.visualViewport?.addEventListener(\"scroll\", measure);\n return () => {\n observer?.disconnect();\n view.removeEventListener(\"resize\", measure);\n view.removeEventListener(\"scroll\", measure, true);\n view.visualViewport?.removeEventListener(\"resize\", measure);\n view.visualViewport?.removeEventListener(\"scroll\", measure);\n };\n }, [open, enabled, root, input]);\n return position;\n}\n\nfunction SearchTypeIcon({ kind }: { kind: string }) {\n const type = TYPE_ICONS[kind];\n return <HugeiconsIcon icon={type?.icon ?? Search01Icon} strokeWidth={2} className={cn(\"size-4 shrink-0\", type?.color ?? \"text-muted-foreground\")} data-search-kind={kind} aria-hidden />;\n}\n\nfunction SearchDate({ value, formatter }: { value?: string; formatter: Intl.DateTimeFormat }) {\n if (!value || Number.isNaN(Date.parse(value))) return null;\n return <time dateTime={value} className=\"shrink-0 text-xs text-muted-foreground\">{formatter.format(new Date(value))}</time>;\n}\n\n/**\n * A search field suggesting contents and groups as the reader types, and\n * recent searches while it is empty; Enter searches, or opens the suggestion chosen.\n */\nexport function SearchBox(p: SearchBoxProps) {\n const { t, error, language } = useMessages();\n const id = useId();\n const navigate = useContext(ContentKitContext)?.navigate;\n const [text, setText] = useState(p.defaultValue ?? \"\");\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(-1);\n const root = useRef<HTMLDivElement>(null);\n const panel = useRef<HTMLDivElement>(null);\n const input = useRef<HTMLInputElement>(null);\n const header = p.presentation === \"header\";\n const anchor = useHeaderAnchor(open, header, root, input);\n const { top } = anchor;\n const dates = useMemo(() => new Intl.DateTimeFormat(language, { dateStyle: \"short\" }), [language]);\n const empty = !text.trim();\n const found = useTypeahead(text, { kind: p.kind, entity_kinds: p.groupKinds, client: p.client });\n const recent = useRecentSearches({ enabled: p.recent !== false && open && empty, client: p.client });\n const items = useMemo<Suggestion[]>(\n () =>\n empty\n ? recent.searches.map((r) => ({ type: \"recent\" as const, query: r.query, searchedAt: r.searched_at }))\n : [...found.contents.map((card) => ({ type: \"content\" as const, card })), ...found.entities.map((group) => ({ type: \"group\" as const, group }))],\n [empty, recent.searches, found.contents, found.entities],\n );\n const current = empty || found.query === text.trim();\n const visible = current ? items : [];\n const selected = visible[active];\n const loading = empty ? recent.loading : !current || found.loading;\n const showRecent = empty && p.recent !== false;\n const emptyMessage = empty ? !header && showRecent && !recent.error ? \"contents.noRecentSearches\" : \"contents.searchHint\" : \"contents.noResults\";\n useEffect(() => {\n if (!open) return;\n const outside = (event: PointerEvent) => {\n if (!root.current?.contains(event.target as Node) && !panel.current?.contains(event.target as Node)) setOpen(false);\n };\n document.addEventListener(\"pointerdown\", outside);\n return () => document.removeEventListener(\"pointerdown\", outside);\n }, [open]);\n const reveal = () => {\n setOpen(true);\n };\n const search = (q: string) => {\n setOpen(false);\n if (q) p.onSearch(q);\n };\n const go = (s: Suggestion) => {\n if (s.type === \"recent\") {\n setText(s.query);\n return search(s.query);\n }\n const url = p.href ? p.href(s.type === \"content\" ? s.card : s.group) : s.type === \"content\" ? s.card.path : s.group.path;\n setOpen(false);\n if (!url) return;\n if (navigate) navigate(url);\n else location.assign(url);\n };\n const panelKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n input.current?.focus();\n setOpen(false);\n setActive(-1);\n };\n const results = (<>\n {showRecent && (\n <div className={cn(\"flex items-center justify-between gap-2 text-muted-foreground\", header ? \"mb-4 text-base font-semibold\" : \"px-2 py-1 text-xs\")}>\n <span id={`${id}-recent`} className=\"flex items-center gap-2\">{header && <HugeiconsIcon icon={Clock01Icon} strokeWidth={2} className=\"size-5\" aria-hidden />}{t(\"contents.recentSearches\")}</span>\n {visible.length > 0 && <button\n type=\"button\"\n className=\"rounded px-1 hover:text-foreground\"\n onMouseDown={(e) => {\n e.preventDefault();\n }}\n onClick={() => void recent.clear()}\n >\n {t(header ? \"contents.clearAllRecent\" : \"contents.clearRecent\")}\n </button>}\n </div>\n )}\n <ul id={`${id}-list`} role=\"listbox\" aria-label={empty ? t(\"contents.recentSearches\") : t(\"contents.suggestions\")} className={cn(\"grid\", header && \"gap-2\")}>\n {visible.map((s, i) => (\n <li\n key={s.type === \"content\" ? `c:${s.card.id}` : s.type === \"group\" ? `g:${s.group.id}` : `r:${s.query}`}\n id={`${id}-${i}`}\n role=\"option\"\n aria-selected={i === active}\n data-ckui=\"suggestion\"\n data-type={s.type}\n className={cn(\"flex cursor-pointer items-center\", header ? s.type === \"recent\" ? \"gap-2 rounded-md p-3 text-base hover:bg-foreground/10\" : \"gap-3 rounded-md px-4 py-1 text-base font-medium hover:bg-foreground/10\" : \"gap-2 px-2 py-1.5\", i === active && \"bg-accent text-accent-foreground\")}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => {\n e.preventDefault();\n go(s);\n }}\n >\n {header && s.type !== \"recent\" ? (\n <>\n <SearchTypeIcon kind={s.type === \"content\" ? s.card.kind : s.group.kind} />\n <span className=\"sr-only\">{labelOf(p.labels, s.type === \"content\" ? s.card.kind : s.group.kind)}</span>\n <span className=\"min-w-0 flex-1 truncate\">{s.type === \"content\" ? s.card.title || s.card.code : s.group.name || s.group.slug}</span>\n </>\n ) : s.type === \"content\" ? (\n <>\n <span className=\"h-10 w-8 shrink-0 overflow-hidden rounded bg-muted\">\n <RenditionImg outputs={s.card.cover} alt=\"\" fit=\"cover\" className=\"size-full\" />\n </span>\n <span className=\"min-w-0 truncate\">{s.card.title || s.card.code}</span>\n </>\n ) : s.type === \"group\" ? (\n <>\n <span className=\"min-w-0 flex-1 truncate\">{s.group.name || s.group.slug}</span>\n <span className=\"text-xs text-muted-foreground\">{labelOf(p.labels, s.group.kind)}</span>\n </>\n ) : (\n <>\n <HugeiconsIcon icon={header ? Search01Icon : Clock01Icon} strokeWidth={2} className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />\n <span className=\"min-w-0 flex-1 truncate\">{s.query}</span>\n {header && anchor.width >= 320 && <SearchDate value={s.searchedAt} formatter={dates} />}\n <button\n type=\"button\"\n className=\"rounded p-0.5 text-muted-foreground hover:text-foreground\"\n aria-label={t(\"contents.removeRecent\", { q: s.query })}\n onMouseDown={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n onClick={() => void recent.clear(s.query)}\n >\n <HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n </button>\n </>\n )}\n </li>\n ))}\n </ul>\n {loading ? <div role=\"status\" className={cn(\"text-muted-foreground\", header ? \"flex justify-center py-4\" : \"px-3 py-2\")}>{header ? <><span className=\"size-6 animate-spin rounded-full border-2 border-muted border-t-foreground motion-reduce:animate-none\" aria-hidden /><span className=\"sr-only\">{t(\"contents.loading\")}</span></> : t(\"contents.loading\")}</div>\n : !empty && found.error ? <p role=\"alert\" className={cn(\"px-3 py-2 text-destructive\", header && \"text-center\")}>{error(found.error)}</p>\n : visible.length === 0 && <div role=\"status\" className={cn(\"text-muted-foreground\", header ? \"flex flex-col items-center gap-2 py-8 text-center\" : \"px-3 py-2\")}>{header && <HugeiconsIcon icon={Search01Icon} strokeWidth={2} className=\"size-8\" aria-hidden />}<p>{t(emptyMessage, { q: text.trim() })}</p></div>}\n </>);\n return (\n <ContentKitUiRoot ref={root} appearance={p.appearance} className={cn(\"relative text-sm\", p.className)} data-ckui=\"search-box\" onBlur={(event) => { if (!event.currentTarget.contains(event.relatedTarget) && !panel.current?.contains(event.relatedTarget)) setOpen(false); }}>\n <form\n role=\"search\"\n className=\"relative\"\n onSubmit={(e) => {\n e.preventDefault();\n if (open && selected) return go(selected);\n search(text.trim());\n }}\n >\n {header ? <button type=\"submit\" className=\"absolute top-1/2 left-2.5 -translate-y-1/2 rounded text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring\" aria-label={t(\"contents.search\")}><HugeiconsIcon icon={Search01Icon} strokeWidth={2} className=\"size-4\" aria-hidden /></button>\n : <HugeiconsIcon icon={Search01Icon} strokeWidth={2} className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" aria-hidden />}\n <Input\n ref={input}\n type={header ? \"text\" : \"search\"}\n role=\"combobox\"\n aria-label={t(\"contents.search\")}\n aria-expanded={open}\n aria-controls={`${id}-list`}\n aria-activedescendant={open && selected ? `${id}-${active}` : undefined}\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n className={cn(\"h-9 ps-8\", header && \"rounded-full border-border/50 bg-foreground/10 pe-9 text-base shadow-none md:text-base\")}\n value={text}\n placeholder={p.placeholder ?? t(\"contents.searchPlaceholder\")}\n onChange={(e) => {\n setText(e.target.value);\n setOpen(true);\n setActive(-1);\n }}\n onFocus={reveal}\n onClick={reveal}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n setOpen(false);\n setActive(-1);\n return;\n }\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n reveal();\n setActive((a) => open ? Math.min(visible.length - 1, a + 1) : 0);\n } else if (e.key === \"ArrowUp\" && open) {\n e.preventDefault();\n setActive((a) => Math.max(-1, a - 1));\n }\n }}\n />\n {header && (text || open) && (\n <button\n type=\"button\"\n className=\"absolute top-1/2 right-2.5 -translate-y-1/2 rounded p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring\"\n aria-label={text ? t(\"contents.clearSearch\") : t(\"common.close\")}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n input.current?.focus();\n setActive(-1);\n if (text) { setText(\"\"); setOpen(true); }\n else setOpen(false);\n }}\n ><HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} className=\"size-4\" aria-hidden /></button>\n )}\n </form>\n {open && (header ? createPortal(\n <ContentKitUiRoot appearance={p.appearance} className=\"fixed inset-x-0 bottom-0 z-[70] text-sm\" style={{ top }} data-ckui=\"search-layer\">\n <div className=\"absolute inset-0 bg-black/30 backdrop-blur-sm\" data-ckui=\"search-backdrop\" aria-hidden />\n <div ref={panel} style={{ width: anchor.width, marginLeft: anchor.left }} className=\"relative origin-top animate-[search-expand_300ms_ease-out] rounded-lg border border-border bg-background text-foreground shadow-lg transition-none motion-reduce:animate-none\" data-ckui=\"search-panel\" onKeyDown={panelKeyDown}>\n <div className=\"w-full px-3 pt-3\">\n <div className=\"[--search-max-height:70vh] overflow-y-auto pb-7 md:[--search-max-height:60vh]\" style={{ maxHeight: `min(var(--search-max-height), calc(100dvh - ${top}px - 1.875rem))` }}>\n <div>{results}</div>\n </div>\n </div>\n </div>\n </ContentKitUiRoot>, document.body,\n ) : <div ref={panel} className=\"absolute top-full z-20 mt-1 grid max-h-96 w-full overflow-auto rounded-md border border-border bg-popover py-1 text-popover-foreground shadow-md\" data-ckui=\"search-panel\" onKeyDown={panelKeyDown}>{results}</div>)}\n\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"search.js","names":[],"sources":["../../../src/components/content/search.tsx"],"sourcesContent":["import { Cancel01Icon, Clock01Icon, File01Icon, Folder01Icon, Image01Icon, Search01Icon, TagsIcon, UserIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon, type IconSvgElement } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, type RefObject, type KeyboardEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Card, GroupCard } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext } from \"../../react/context.js\";\nimport { useRecentSearches, useTypeahead } from \"../../react/discovery.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Input } from \"#ckui/ui/input\";\nimport { RenditionImg } from \"../rendition-img.js\";\nimport { labelOf, type Labels } from \"../groups/parts.js\";\n\nexport interface SearchBoxProps {\n /** Submits the text: the host shows its search page. */\n onSearch: (q: string) => void;\n /** Suggest contents of this kind only. */\n kind?: string;\n /** The group kinds suggested; every kind with a page by default. */\n groupKinds?: readonly string[];\n defaultValue?: string;\n placeholder?: string;\n /** A suggestion's link; default its canonical path. */\n href?: (item: Card | GroupCard) => string | undefined;\n labels?: Labels;\n /** The reader's recent searches while the box is empty. Default true. */\n recent?: boolean;\n /** A portal dropdown anchored to the header field; default stays inline. */\n presentation?: \"inline\" | \"header\";\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\ntype Suggestion = { type: \"content\"; card: Card } | { type: \"group\"; group: GroupCard } | { type: \"recent\"; query: string };\n\nconst TYPE_ICONS: Record<string, { icon: IconSvgElement; color: string }> = {\n artist: { icon: UserIcon, color: \"text-blue-500 dark:text-blue-400\" },\n series: { icon: Folder01Icon, color: \"text-yellow-600 dark:text-yellow-400\" },\n gallery: { icon: Image01Icon, color: \"text-green-600 dark:text-green-400\" },\n post: { icon: File01Icon, color: \"text-purple-500 dark:text-purple-400\" },\n blog: { icon: File01Icon, color: \"text-purple-500 dark:text-purple-400\" },\n poll: { icon: File01Icon, color: \"text-purple-500 dark:text-purple-400\" },\n character: { icon: UserIcon, color: \"text-purple-500 dark:text-purple-400\" },\n tag: { icon: TagsIcon, color: \"text-orange-500 dark:text-orange-400\" },\n};\n\nfunction useHeaderAnchor(open: boolean, enabled: boolean, root: RefObject<HTMLDivElement | null>, input: RefObject<HTMLInputElement | null>) {\n const [position, setPosition] = useState({ top: 0, left: 0, width: 0 });\n useLayoutEffect(() => {\n if (!open || !enabled || !root.current) return;\n const anchor = input.current ?? root.current;\n const view = root.current.ownerDocument.defaultView;\n if (!view) return;\n const measure = () => {\n const rect = anchor.getBoundingClientRect();\n setPosition({ top: Math.max(0, Math.min(view.innerHeight, rect.bottom + 4)), left: rect.left, width: rect.width });\n };\n measure();\n const observer = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(measure);\n observer?.observe(anchor);\n view.addEventListener(\"resize\", measure);\n view.addEventListener(\"scroll\", measure, true);\n view.visualViewport?.addEventListener(\"resize\", measure);\n view.visualViewport?.addEventListener(\"scroll\", measure);\n return () => {\n observer?.disconnect();\n view.removeEventListener(\"resize\", measure);\n view.removeEventListener(\"scroll\", measure, true);\n view.visualViewport?.removeEventListener(\"resize\", measure);\n view.visualViewport?.removeEventListener(\"scroll\", measure);\n };\n }, [open, enabled, root, input]);\n return position;\n}\n\nfunction SearchTypeIcon({ kind }: { kind: string }) {\n const type = TYPE_ICONS[kind];\n return <HugeiconsIcon icon={type?.icon ?? Search01Icon} strokeWidth={2} className={cn(\"size-4 shrink-0\", type?.color ?? \"text-muted-foreground\")} data-search-kind={kind} aria-hidden />;\n}\n\n/**\n * A search field suggesting contents and groups as the reader types, and\n * recent searches while it is empty; Enter searches, or opens the suggestion chosen.\n */\nexport function SearchBox(p: SearchBoxProps) {\n const { t, error } = useMessages();\n const id = useId();\n const navigate = useContext(ContentKitContext)?.navigate;\n const [text, setText] = useState(p.defaultValue ?? \"\");\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(-1);\n const root = useRef<HTMLDivElement>(null);\n const panel = useRef<HTMLDivElement>(null);\n const input = useRef<HTMLInputElement>(null);\n const header = p.presentation === \"header\";\n const anchor = useHeaderAnchor(open, header, root, input);\n const { top } = anchor;\n const empty = !text.trim();\n const found = useTypeahead(text, { kind: p.kind, entity_kinds: p.groupKinds, client: p.client });\n const recent = useRecentSearches({ enabled: p.recent !== false && open && empty, client: p.client });\n const items = useMemo<Suggestion[]>(\n () =>\n empty\n ? recent.searches.map((r) => ({ type: \"recent\" as const, query: r.query }))\n : [...found.contents.map((card) => ({ type: \"content\" as const, card })), ...found.entities.map((group) => ({ type: \"group\" as const, group }))],\n [empty, recent.searches, found.contents, found.entities],\n );\n const current = empty || found.query === text.trim();\n const visible = current ? items : [];\n const selected = visible[active];\n const loading = empty ? recent.loading : !current || found.loading;\n const showRecent = empty && p.recent !== false;\n const emptyMessage = empty ? !header && showRecent && !recent.error ? \"contents.noRecentSearches\" : \"contents.searchHint\" : \"contents.noResults\";\n useEffect(() => {\n if (!open) return;\n const outside = (event: PointerEvent) => {\n if (!root.current?.contains(event.target as Node) && !panel.current?.contains(event.target as Node)) setOpen(false);\n };\n document.addEventListener(\"pointerdown\", outside);\n return () => document.removeEventListener(\"pointerdown\", outside);\n }, [open]);\n const reveal = () => {\n setOpen(true);\n };\n const search = (q: string) => {\n setOpen(false);\n if (q) p.onSearch(q);\n };\n const go = (s: Suggestion) => {\n if (s.type === \"recent\") {\n setText(s.query);\n return search(s.query);\n }\n const url = p.href ? p.href(s.type === \"content\" ? s.card : s.group) : s.type === \"content\" ? s.card.path : s.group.path;\n setOpen(false);\n if (!url) return;\n if (navigate) navigate(url);\n else location.assign(url);\n };\n const panelKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n input.current?.focus();\n setOpen(false);\n setActive(-1);\n };\n const results = (<>\n {showRecent && (\n <div className={cn(\"flex items-center justify-between gap-2 text-muted-foreground\", header ? \"mb-4 text-base font-semibold\" : \"px-2 py-1 text-xs\")}>\n <span id={`${id}-recent`} className=\"flex items-center gap-2\">{header && <HugeiconsIcon icon={Clock01Icon} strokeWidth={2} className=\"size-5\" aria-hidden />}{t(\"contents.recentSearches\")}</span>\n {visible.length > 0 && <button\n type=\"button\"\n className=\"rounded px-1 hover:text-foreground\"\n onMouseDown={(e) => {\n e.preventDefault();\n }}\n onClick={() => void recent.clear()}\n >\n {t(header ? \"contents.clearAllRecent\" : \"contents.clearRecent\")}\n </button>}\n </div>\n )}\n <ul id={`${id}-list`} role=\"listbox\" aria-label={empty ? t(\"contents.recentSearches\") : t(\"contents.suggestions\")} className={cn(\"grid\", header && \"gap-2\")}>\n {visible.map((s, i) => (\n <li\n key={s.type === \"content\" ? `c:${s.card.id}` : s.type === \"group\" ? `g:${s.group.id}` : `r:${s.query}`}\n id={`${id}-${i}`}\n role=\"option\"\n aria-selected={i === active}\n data-ckui=\"suggestion\"\n data-type={s.type}\n className={cn(\"flex cursor-pointer items-center\", header ? s.type === \"recent\" ? \"gap-2 rounded-md p-3 text-base hover:bg-foreground/10\" : \"gap-3 rounded-md px-4 py-1 text-base font-medium hover:bg-foreground/10\" : \"gap-2 px-2 py-1.5\", i === active && \"bg-accent text-accent-foreground\")}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => {\n e.preventDefault();\n go(s);\n }}\n >\n {header && s.type !== \"recent\" ? (\n <>\n <SearchTypeIcon kind={s.type === \"content\" ? s.card.kind : s.group.kind} />\n <span className=\"sr-only\">{labelOf(p.labels, s.type === \"content\" ? s.card.kind : s.group.kind)}</span>\n <span className=\"min-w-0 flex-1 truncate\">{s.type === \"content\" ? s.card.title || s.card.code : s.group.name || s.group.slug}</span>\n </>\n ) : s.type === \"content\" ? (\n <>\n <span className=\"h-10 w-8 shrink-0 overflow-hidden rounded bg-muted\">\n <RenditionImg outputs={s.card.cover} alt=\"\" fit=\"cover\" className=\"size-full\" />\n </span>\n <span className=\"min-w-0 truncate\">{s.card.title || s.card.code}</span>\n </>\n ) : s.type === \"group\" ? (\n <>\n <span className=\"min-w-0 flex-1 truncate\">{s.group.name || s.group.slug}</span>\n <span className=\"text-xs text-muted-foreground\">{labelOf(p.labels, s.group.kind)}</span>\n </>\n ) : (\n <>\n <HugeiconsIcon icon={header ? Search01Icon : Clock01Icon} strokeWidth={2} className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />\n <span className=\"min-w-0 flex-1 truncate\">{s.query}</span>\n <button\n type=\"button\"\n className=\"rounded p-0.5 text-muted-foreground hover:text-foreground\"\n aria-label={t(\"contents.removeRecent\", { q: s.query })}\n onMouseDown={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n onClick={() => void recent.clear(s.query)}\n >\n <HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n </button>\n </>\n )}\n </li>\n ))}\n </ul>\n {loading ? <div role=\"status\" className={cn(\"text-muted-foreground\", header ? \"flex justify-center py-4\" : \"px-3 py-2\")}>{header ? <><span className=\"size-6 animate-spin rounded-full border-2 border-muted border-t-foreground motion-reduce:animate-none\" aria-hidden /><span className=\"sr-only\">{t(\"contents.loading\")}</span></> : t(\"contents.loading\")}</div>\n : !empty && found.error ? <p role=\"alert\" className={cn(\"px-3 py-2 text-destructive\", header && \"text-center\")}>{error(found.error)}</p>\n : visible.length === 0 && <div role=\"status\" className={cn(\"text-muted-foreground\", header ? \"flex flex-col items-center gap-2 py-8 text-center\" : \"px-3 py-2\")}>{header && <HugeiconsIcon icon={Search01Icon} strokeWidth={2} className=\"size-8\" aria-hidden />}<p>{t(emptyMessage, { q: text.trim() })}</p></div>}\n </>);\n return (\n <ContentKitUiRoot ref={root} appearance={p.appearance} className={cn(\"relative text-sm\", p.className)} data-ckui=\"search-box\" onBlur={(event) => { if (!event.currentTarget.contains(event.relatedTarget) && !panel.current?.contains(event.relatedTarget)) setOpen(false); }}>\n <form\n role=\"search\"\n className=\"relative\"\n onSubmit={(e) => {\n e.preventDefault();\n if (open && selected) return go(selected);\n search(text.trim());\n }}\n >\n {header ? <button type=\"submit\" className=\"absolute top-1/2 left-2.5 -translate-y-1/2 rounded text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring\" aria-label={t(\"contents.search\")}><HugeiconsIcon icon={Search01Icon} strokeWidth={2} className=\"size-4\" aria-hidden /></button>\n : <HugeiconsIcon icon={Search01Icon} strokeWidth={2} className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" aria-hidden />}\n <Input\n ref={input}\n type={header ? \"text\" : \"search\"}\n role=\"combobox\"\n aria-label={t(\"contents.search\")}\n aria-expanded={open}\n aria-controls={`${id}-list`}\n aria-activedescendant={open && selected ? `${id}-${active}` : undefined}\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n className={cn(\"h-9 ps-8\", header && \"rounded-full border-border/50 bg-foreground/10 pe-9 text-base shadow-none md:text-base\")}\n value={text}\n placeholder={p.placeholder ?? t(\"contents.searchPlaceholder\")}\n onChange={(e) => {\n setText(e.target.value);\n setOpen(true);\n setActive(-1);\n }}\n onFocus={reveal}\n onClick={reveal}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n setOpen(false);\n setActive(-1);\n return;\n }\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n reveal();\n setActive((a) => open ? Math.min(visible.length - 1, a + 1) : 0);\n } else if (e.key === \"ArrowUp\" && open) {\n e.preventDefault();\n setActive((a) => Math.max(-1, a - 1));\n }\n }}\n />\n {header && (text || open) && (\n <button\n type=\"button\"\n className=\"absolute top-1/2 right-2.5 -translate-y-1/2 rounded p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring\"\n aria-label={text ? t(\"contents.clearSearch\") : t(\"common.close\")}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => {\n input.current?.focus();\n setActive(-1);\n if (text) { setText(\"\"); setOpen(true); }\n else setOpen(false);\n }}\n ><HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} className=\"size-4\" aria-hidden /></button>\n )}\n </form>\n {open && (header ? createPortal(\n <ContentKitUiRoot appearance={p.appearance} className=\"fixed inset-x-0 bottom-0 z-[70] text-sm\" style={{ top }} data-ckui=\"search-layer\">\n <div className=\"absolute inset-0 bg-black/30 backdrop-blur-sm\" data-ckui=\"search-backdrop\" aria-hidden />\n <div ref={panel} style={{ width: anchor.width, marginLeft: anchor.left }} className=\"relative origin-top animate-[search-expand_300ms_ease-out] rounded-lg border border-border bg-background text-foreground shadow-lg transition-none motion-reduce:animate-none\" data-ckui=\"search-panel\" onKeyDown={panelKeyDown}>\n <div className=\"w-full px-3 pt-3\">\n <div className=\"[--search-max-height:70vh] overflow-y-auto pb-7 md:[--search-max-height:60vh]\" style={{ maxHeight: `min(var(--search-max-height), calc(100dvh - ${top}px - 1.875rem))` }}>\n <div>{results}</div>\n </div>\n </div>\n </div>\n </ContentKitUiRoot>, document.body,\n ) : <div ref={panel} className=\"absolute top-full z-20 mt-1 grid max-h-96 w-full overflow-auto rounded-md border border-border bg-popover py-1 text-popover-foreground shadow-md\" data-ckui=\"search-panel\" onKeyDown={panelKeyDown}>{results}</div>)}\n\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -49,25 +49,25 @@ import { GroupBanner as ue, GroupImageEditor as de, MembershipBox as fe } from "
49
49
  import { GroupEditor as pe, GroupMergeDialog as me } from "./components/groups/editor.js";
50
50
  import { GroupMembers as he, MembershipEditor as ge } from "./components/groups/memberships.js";
51
51
  import { ContentCard as _e, OwnerChip as ve, PostCard as ye, lockLabel as be } from "./components/content/card.js";
52
- import { CardGrid as xe, ContentGrid as Se, ContentHistory as Ce, ContentRail as we, SearchResults as Te } from "./components/content/grid.js";
53
- import { DailyReleases as Ee } from "./components/content/daily-releases.js";
54
- import { PopularContentGrid as De } from "./components/content/popular.js";
55
- import { SearchBox as Oe } from "./components/content/search.js";
56
- import { ContentFilterSettings as ke, ReleaseDateIndex as Ae } from "./components/content/filters.js";
57
- import { ReaderSettings as je } from "./components/content/reader-settings.js";
58
- import { ContentListing as Me, sortLabel as Ne } from "./components/content/listing.js";
59
- import { ReaderManifestEditor as Pe } from "./components/admin/reader-manifest.js";
60
- import { MediaItemPanel as Fe, VideoMediaEditor as Ie, videoPaths as Le } from "./components/admin/media-item-panel.js";
61
- import { AccessEditor as Re, ContentDetailsEditor as ze, ContentSections as Be, SegmentsEditor as Ve, VersionCover as He, VersionsEditor as Ue, versionLabel as We } from "./components/content/editors.js";
62
- import { ReaderStats as Ge } from "./components/content/reader-stats.js";
63
- import { VersionDownloadButton as Ke } from "./components/content/download-button.js";
64
- import { ContentEditor as qe, ContentManager as Je, contentStatus as Ye, useContentManagerAccess as Xe } from "./components/admin/content-manager.js";
65
- import { GroupManager as Ze, useGroupManagerAccess as Qe } from "./components/admin/group-manager.js";
66
- import { PollManager as $e, pollState as et, usePollManagerAccess as tt } from "./components/admin/poll-manager.js";
67
- import { StatsDashboard as nt } from "./components/admin/stats-dashboard.js";
68
- import { ContentAdmin as rt } from "./components/admin/content-admin.js";
69
- import { UserCommentStanding as it, useUserCommentStandingAccess as at } from "./components/admin/user-comment-standing.js";
70
- import { UploadQueue as ot } from "./components/admin/upload-queue.js";
71
- import { NotificationBell as st, NotificationInbox as ct } from "./components/notifications.js";
72
- import { BillingNotification as lt, billingNotificationAction as ut, isBillingNotification as dt } from "./components/billing-notification.js";
73
- export { Re as AccessEditor, O as AvatarUpload, z as BanNotice, q as BannedWords, lt as BillingNotification, xe as CardGrid, B as CommentBanDialog, V as CommentBans, Y as CommentModeration, H as Comments, rt as ContentAdmin, _e as ContentCard, ze as ContentDetailsEditor, qe as ContentEditor, ke as ContentFilterSettings, Se as ContentGrid, Ce as ContentHistory, l as ContentKitUiProvider, c as ContentKitUiRoot, Me as ContentListing, Je as ContentManager, we as ContentRail, Be as ContentSections, k as CoverUpload, Ee as DailyReleases, e as DensityContext, u as EncodeProgress, U as FavoriteButton, Z as GroupAvatar, ue as GroupBanner, Q as GroupCover, ne as GroupDirectory, pe as GroupEditor, re as GroupHeader, de as GroupImageEditor, $ as GroupLink, Ze as GroupManager, he as GroupMembers, me as GroupMergeDialog, ee as GroupPicker, N as HoverPreview, J as IPBans, p as ImageCropDialog, P as LazyMount, j as MediaFolderEditor, E as MediaGallery, Fe as MediaItemPanel, F as MediaReadinessNotice, fe as MembershipBox, ge as MembershipEditor, I as NoAccess, st as NotificationBell, ct as NotificationInbox, le as OfferFields, ve as OwnerChip, L as Pager, ae as Paywall, G as Poll, K as PollEditor, $e as PollManager, De as PopularContentGrid, ye as PostCard, W as ReactionButtons, Pe as ReaderManifestEditor, je as ReaderSettings, Ge as ReaderStats, Ae as ReleaseDateIndex, t as RenditionImg, Oe as SearchBox, Te as SearchResults, Ve as SegmentsEditor, h as SlotEditError, g as SlotEditMenu, _ as SlotEditor, m as SlotImage, A as SortableList, C as SpriteFrame, nt as StatsDashboard, ot as UploadQueue, it as UserCommentStanding, He as VersionCover, Ke as VersionDownloadButton, oe as VersionPicker, Ue as VersionsEditor, Ie as VideoMediaEditor, D as VideoMiniPlayer, w as VideoPlayer, y as VideoPoster, b as VideoPosterPicker, ut as billingNotificationAction, Ye as contentStatus, r as createTranslator, i as defaultMessages, a as defineMessages, M as describeRules, d as encodeLabel, ie as formatAttribute, f as formatRemaining, x as formatTime, dt as isBillingNotification, te as labelOf, be as lockLabel, S as playerButtonClass, et as pollState, se as priceLabel, T as qualityLabel, o as resolveMessages, Ne as sortLabel, X as useCommentModerationAccess, R as useConfirm, Xe as useContentManagerAccess, Qe as useGroupManagerAccess, s as useMessages, tt as usePollManagerAccess, n as useRendition, v as useSlotEditor, at as useUserCommentStandingAccess, ce as useVersionMenuItems, We as versionLabel, Le as videoPaths };
52
+ import { CardGrid as xe, ContentGrid as Se, ContentHistory as Ce, ContentRail as we, SearchResults as Te, cardGridLayout as Ee } from "./components/content/grid.js";
53
+ import { DailyReleases as De } from "./components/content/daily-releases.js";
54
+ import { PopularContentGrid as Oe } from "./components/content/popular.js";
55
+ import { SearchBox as ke } from "./components/content/search.js";
56
+ import { ContentFilterSettings as Ae, ReleaseDateIndex as je } from "./components/content/filters.js";
57
+ import { ReaderSettings as Me } from "./components/content/reader-settings.js";
58
+ import { ContentListing as Ne, sortLabel as Pe } from "./components/content/listing.js";
59
+ import { ReaderManifestEditor as Fe } from "./components/admin/reader-manifest.js";
60
+ import { MediaItemPanel as Ie, VideoMediaEditor as Le, videoPaths as Re } from "./components/admin/media-item-panel.js";
61
+ import { AccessEditor as ze, ContentDetailsEditor as Be, ContentSections as Ve, SegmentsEditor as He, VersionCover as Ue, VersionsEditor as We, versionLabel as Ge } from "./components/content/editors.js";
62
+ import { ReaderStats as Ke } from "./components/content/reader-stats.js";
63
+ import { VersionDownloadButton as qe } from "./components/content/download-button.js";
64
+ import { ContentEditor as Je, ContentManager as Ye, contentStatus as Xe, useContentManagerAccess as Ze } from "./components/admin/content-manager.js";
65
+ import { GroupManager as Qe, useGroupManagerAccess as $e } from "./components/admin/group-manager.js";
66
+ import { PollManager as et, pollState as tt, usePollManagerAccess as nt } from "./components/admin/poll-manager.js";
67
+ import { StatsDashboard as rt } from "./components/admin/stats-dashboard.js";
68
+ import { ContentAdmin as it } from "./components/admin/content-admin.js";
69
+ import { UserCommentStanding as at, useUserCommentStandingAccess as ot } from "./components/admin/user-comment-standing.js";
70
+ import { UploadQueue as st } from "./components/admin/upload-queue.js";
71
+ import { NotificationBell as ct, NotificationInbox as lt } from "./components/notifications.js";
72
+ import { BillingNotification as ut, billingNotificationAction as dt, isBillingNotification as ft } from "./components/billing-notification.js";
73
+ export { ze as AccessEditor, O as AvatarUpload, z as BanNotice, q as BannedWords, ut as BillingNotification, xe as CardGrid, B as CommentBanDialog, V as CommentBans, Y as CommentModeration, H as Comments, it as ContentAdmin, _e as ContentCard, Be as ContentDetailsEditor, Je as ContentEditor, Ae as ContentFilterSettings, Se as ContentGrid, Ce as ContentHistory, l as ContentKitUiProvider, c as ContentKitUiRoot, Ne as ContentListing, Ye as ContentManager, we as ContentRail, Ve as ContentSections, k as CoverUpload, De as DailyReleases, e as DensityContext, u as EncodeProgress, U as FavoriteButton, Z as GroupAvatar, ue as GroupBanner, Q as GroupCover, ne as GroupDirectory, pe as GroupEditor, re as GroupHeader, de as GroupImageEditor, $ as GroupLink, Qe as GroupManager, he as GroupMembers, me as GroupMergeDialog, ee as GroupPicker, N as HoverPreview, J as IPBans, p as ImageCropDialog, P as LazyMount, j as MediaFolderEditor, E as MediaGallery, Ie as MediaItemPanel, F as MediaReadinessNotice, fe as MembershipBox, ge as MembershipEditor, I as NoAccess, ct as NotificationBell, lt as NotificationInbox, le as OfferFields, ve as OwnerChip, L as Pager, ae as Paywall, G as Poll, K as PollEditor, et as PollManager, Oe as PopularContentGrid, ye as PostCard, W as ReactionButtons, Fe as ReaderManifestEditor, Me as ReaderSettings, Ke as ReaderStats, je as ReleaseDateIndex, t as RenditionImg, ke as SearchBox, Te as SearchResults, He as SegmentsEditor, h as SlotEditError, g as SlotEditMenu, _ as SlotEditor, m as SlotImage, A as SortableList, C as SpriteFrame, rt as StatsDashboard, st as UploadQueue, at as UserCommentStanding, Ue as VersionCover, qe as VersionDownloadButton, oe as VersionPicker, We as VersionsEditor, Le as VideoMediaEditor, D as VideoMiniPlayer, w as VideoPlayer, y as VideoPoster, b as VideoPosterPicker, dt as billingNotificationAction, Ee as cardGridLayout, Xe as contentStatus, r as createTranslator, i as defaultMessages, a as defineMessages, M as describeRules, d as encodeLabel, ie as formatAttribute, f as formatRemaining, x as formatTime, ft as isBillingNotification, te as labelOf, be as lockLabel, S as playerButtonClass, tt as pollState, se as priceLabel, T as qualityLabel, o as resolveMessages, Pe as sortLabel, X as useCommentModerationAccess, R as useConfirm, Ze as useContentManagerAccess, $e as useGroupManagerAccess, s as useMessages, nt as usePollManagerAccess, n as useRendition, v as useSlotEditor, ot as useUserCommentStandingAccess, ce as useVersionMenuItems, Ge as versionLabel, Re as videoPaths };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openrails/contentkit-ui",
3
- "version": "0.98.4",
3
+ "version": "0.98.6",
4
4
  "description": "ContentKit in the browser: client, React hooks and styled components for media, uploads and content URLs.",
5
5
  "type": "module",
6
6
  "license": "MIT",