@openrails/contentkit-ui 0.90.0 → 0.90.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +80 -0
  2. package/dist/client/browser-search-history.d.ts +24 -0
  3. package/dist/client/browser-search-history.js +92 -0
  4. package/dist/client/browser-search-history.js.map +1 -0
  5. package/dist/client/discovery.d.ts +5 -2
  6. package/dist/client/discovery.js +14 -22
  7. package/dist/client/discovery.js.map +1 -1
  8. package/dist/client.js +14 -14
  9. package/dist/components/admin/content-admin.d.ts +28 -0
  10. package/dist/components/admin/content-admin.js +191 -0
  11. package/dist/components/admin/content-admin.js.map +1 -0
  12. package/dist/components/content/index.d.ts +1 -0
  13. package/dist/components/content/reader-settings.d.ts +19 -0
  14. package/dist/components/content/reader-settings.js +95 -0
  15. package/dist/components/content/reader-settings.js.map +1 -0
  16. package/dist/components/content/search.d.ts +2 -0
  17. package/dist/components/content/search.js +334 -137
  18. package/dist/components/content/search.js.map +1 -1
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +18 -16
  21. package/dist/locales/admin/de.js +10 -0
  22. package/dist/locales/admin/de.js.map +1 -1
  23. package/dist/locales/admin/en.d.ts +10 -0
  24. package/dist/locales/admin/en.js +10 -0
  25. package/dist/locales/admin/en.js.map +1 -1
  26. package/dist/locales/admin/es.js +10 -0
  27. package/dist/locales/admin/es.js.map +1 -1
  28. package/dist/locales/admin/ja.js +10 -0
  29. package/dist/locales/admin/ja.js.map +1 -1
  30. package/dist/locales/admin/ko.js +10 -0
  31. package/dist/locales/admin/ko.js.map +1 -1
  32. package/dist/locales/admin/zh.js +10 -0
  33. package/dist/locales/admin/zh.js.map +1 -1
  34. package/dist/locales/discovery/de.js +9 -0
  35. package/dist/locales/discovery/de.js.map +1 -1
  36. package/dist/locales/discovery/en.d.ts +9 -0
  37. package/dist/locales/discovery/en.js +9 -0
  38. package/dist/locales/discovery/en.js.map +1 -1
  39. package/dist/locales/discovery/es.js +9 -0
  40. package/dist/locales/discovery/es.js.map +1 -1
  41. package/dist/locales/discovery/ja.js +9 -0
  42. package/dist/locales/discovery/ja.js.map +1 -1
  43. package/dist/locales/discovery/ko.js +9 -0
  44. package/dist/locales/discovery/ko.js.map +1 -1
  45. package/dist/locales/discovery/zh.js +9 -0
  46. package/dist/locales/discovery/zh.js.map +1 -1
  47. package/dist/locales/en.d.ts +19 -0
  48. package/dist/react/discovery.d.ts +1 -1
  49. package/dist/react/discovery.js +145 -92
  50. package/dist/react/discovery.js.map +1 -1
  51. package/dist/styles.css +1 -1
  52. package/dist/ui/dialog.js +16 -10
  53. package/dist/ui/dialog.js.map +1 -1
  54. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-admin.js","names":[],"sources":["../../../src/components/admin/content-admin.tsx"],"sourcesContent":["import { useId, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { ContentModel } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useAdminLocation, useFlowClient, type AdminLocation, type AdminNavigation } from \"../../react/admin.js\";\nimport { useKinds } from \"../../react/groups.js\";\nimport { useReadScope } from \"../../react/context.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { labelOf, type Labels } from \"../groups/parts.js\";\nimport { CommentModeration, type CommentModerationProps } from \"../social/moderation.js\";\nimport { ContentManager, type ContentManagerProps } from \"./content-manager.js\";\nimport { GroupManager, type GroupManagerProps } from \"./group-manager.js\";\nimport { PollManager, type PollManagerProps } from \"./poll-manager.js\";\nimport { AdminRoot, LoadFailed, Rows, type AdminFlowProps, type AdminRouteProps } from \"./shell.js\";\nimport { StatsDashboard } from \"./stats-dashboard.js\";\n\nexport type ContentAdminSection = \"contents\" | \"groups\" | \"moderation\" | \"polls\" | \"statistics\";\n\n/** An optional reference workbench; each section remains usable as its own component. */\nexport interface ContentAdminProps extends AdminFlowProps, AdminRouteProps {\n /** Sections in navigation order. Default all. Navigation does not grant access. */\n sections?: readonly ContentAdminSection[];\n /** Content kinds in picker order; default all configured kinds. Unknown kinds are omitted. */\n contentKinds?: readonly string[];\n /** Group kinds in picker order; default the configured site-owned kinds. Unknown kinds are omitted. */\n groupKinds?: readonly string[];\n labels?: Labels;\n content?: Pick<ContentManagerProps, \"renderEditor\" | \"contentHref\">;\n groups?: Pick<GroupManagerProps, \"renderContent\">;\n moderation?: Pick<CommentModerationProps, \"itemHref\" | \"userHref\" | \"sections\">;\n polls?: Pick<PollManagerProps, \"freeText\" | \"maxOptions\">;\n}\n\nconst SECTIONS: readonly ContentAdminSection[] = [\"contents\", \"groups\", \"moderation\", \"polls\", \"statistics\"];\nconst MODERATION: readonly string[] = [\"comments\", \"queue\", \"bans\", \"words\", \"ips\"];\n\n/**\n * Model-driven content, group, moderation, poll and statistics screens, with\n * the host's transport, router and theme. Only the selected manager mounts;\n * its native permissions and refusals remain authoritative. This component\n * does not mount a server portal, sign users in or define a publishing workflow.\n */\nexport function ContentAdmin({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: ContentAdminProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n const scope = useReadScope();\n const [boundary, setBoundary] = useState({ client, scope, revision: 0 });\n if (boundary.client !== client || boundary.scope !== scope) {\n setBoundary({ client, scope, revision: boundary.revision + 1 });\n }\n return (\n <AdminRoot flow=\"content-admin\" guard={guard} appearance={appearance} className={className} language={language} messages={messages}>\n <Workbench key={boundary.revision} {...p} client={client} guard={guard} />\n </AdminRoot>\n );\n}\n\ntype WorkbenchProps = Omit<ContentAdminProps, \"client\" | \"baseUrl\" | \"auth\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\n\nfunction knownKinds(wanted: readonly string[] | undefined, configured: object): string[] {\n return [...new Set(wanted ?? Object.keys(configured).sort())].filter((kind) => Object.hasOwn(configured, kind));\n}\n\nfunction groupKinds(wanted: readonly string[] | undefined, model: ContentModel): string[] {\n return knownKinds(wanted ?? Object.keys(model.group_kinds).filter((kind) => model.group_kinds[kind]?.owner !== \"user\").sort(), model.group_kinds);\n}\n\nfunction decode(part: string | undefined): string | undefined {\n if (part === undefined) return undefined;\n try { return decodeURIComponent(part); } catch { return undefined; }\n}\n\n/** Routes nested managers through the same outer history, including memory-only use. */\nfunction childNavigation(base: string, view: string, loc: AdminLocation): AdminNavigation {\n return {\n pathname: `${base}/${view}`,\n search: loc.query.size ? `?${loc.query}` : \"\",\n navigate(to, options) {\n const target = new URL(to, \"https://contentkit.invalid\");\n if (target.origin !== \"https://contentkit.invalid\") return;\n const prefix = `${base}/`;\n if (target.pathname !== base && !target.pathname.startsWith(prefix)) return;\n loc.go(target.pathname.slice(prefix.length), Object.fromEntries(target.searchParams), options);\n },\n };\n}\n\nfunction Workbench({ client, basePath, navigation, sections: wanted, contentKinds: requestedContents, groupKinds: requestedGroups, labels, guard, onError, content, groups, moderation, polls }: WorkbenchProps) {\n const { t } = useMessages();\n const id = useId();\n const loc = useAdminLocation(basePath, navigation);\n const model = useKinds({ client });\n if (model.loading) return <Rows />;\n if (!model.kinds) return <LoadFailed error={model.error} message={t(\"contentAdmin.modelFailed\")} retry={model.reload} />;\n\n const kinds = knownKinds(requestedContents, model.kinds.kinds);\n const managedGroups = groupKinds(requestedGroups, model.kinds);\n const sections = [...new Set(wanted ?? SECTIONS)].filter((section) =>\n SECTIONS.includes(section) &&\n (section !== \"contents\" && section !== \"statistics\" || kinds.length > 0) &&\n (section !== \"groups\" || managedGroups.length > 0) &&\n (section !== \"moderation\" || moderation?.sections?.length !== 0),\n );\n if (!sections.length) return <p role=\"status\" className=\"text-muted-foreground\">{t(\"contentAdmin.empty\")}</p>;\n\n const parts = loc.view.split(\"/\");\n const section = (loc.view ? parts[0] : sections[0]) as ContentAdminSection;\n const requestedKind = parts[1] === undefined ? undefined : decode(parts[1]);\n const kind = requestedKind ?? kinds[0]!;\n const moderationSections: readonly string[] = moderation?.sections ?? MODERATION;\n const valid = sections.includes(section) &&\n (section !== \"contents\" || (parts[1] === undefined || requestedKind !== undefined) && kinds.includes(kind)) &&\n (section !== \"groups\" || parts[1] === undefined || requestedKind !== undefined && managedGroups.includes(requestedKind)) &&\n (section !== \"moderation\" || !parts[1] || moderationSections.includes(parts[1])) &&\n (section !== \"statistics\" || parts.length === 1 || !loc.view);\n const base = basePath?.replace(/\\/+$/, \"\") ?? \"\";\n const prefix = section === \"contents\" ? `contents/${encodeURIComponent(kind)}` : section;\n const view = loc.view || prefix;\n // A contents root selects the first configured kind without changing the URL.\n const effectiveView = section === \"contents\" && parts[1] === undefined ? prefix : view;\n const nav = childNavigation(base, effectiveView, loc);\n const shared = { client, guard, onError };\n const names: Record<ContentAdminSection, string> = {\n contents: t(\"contentManager.title\"), groups: t(\"contentAdmin.groups\"), moderation: t(\"moderation.title\"), polls: t(\"pollManager.title\"), statistics: t(\"stats.title\"),\n };\n const destination = (s: ContentAdminSection) => s === \"contents\" ? `contents/${encodeURIComponent(kinds[0]!)}` : s;\n\n return (\n <>\n <h1 className=\"text-lg font-semibold\">{t(\"contentAdmin.title\")}</h1>\n <div className=\"grid min-w-0 gap-4 sm:grid-cols-[12rem_minmax(0,1fr)]\">\n <nav aria-label={t(\"contentAdmin.navigation\")} className=\"flex gap-1 overflow-x-auto sm:grid sm:content-start\">\n {sections.map((s) => (\n <Button key={s} variant={section === s ? \"secondary\" : \"ghost\"} className=\"justify-start whitespace-nowrap\" aria-current={section === s ? \"page\" : undefined} onClick={() => loc.go(destination(s))}>\n {names[s]}\n </Button>\n ))}\n </nav>\n <div className=\"grid min-w-0 content-start gap-4\" data-ckui=\"content-admin-view\">\n {!valid ? (\n <div className=\"grid justify-items-start gap-2\">\n <p role=\"status\">{t(\"contentAdmin.unavailable\")}</p>\n <Button variant=\"outline\" onClick={() => loc.go(\"\")}>{t(\"contentAdmin.back\")}</Button>\n </div>\n ) : section === \"contents\" ? (\n <>\n <label className=\"grid justify-items-start gap-1 text-sm\" htmlFor={`${id}-kind`}>\n {t(\"contentAdmin.kind\")}\n <select id={`${id}-kind`} className=\"h-8 rounded-md border border-input bg-background px-2 text-sm\" value={kind} onChange={(event) => loc.go(`contents/${encodeURIComponent(event.target.value)}`)}>\n {kinds.map((k) => <option key={k} value={k}>{labelOf(labels, k)}</option>)}\n </select>\n </label>\n <ContentManager key={kind} {...shared} {...content} kind={kind} labels={labels} languages={model.kinds.languages} basePath={`${base}/${prefix}`} navigation={nav} />\n </>\n ) : section === \"groups\" ? (\n <GroupManager {...shared} {...groups} labels={labels} groupKinds={managedGroups} basePath={`${base}/groups`} navigation={nav} />\n ) : section === \"moderation\" ? (\n <CommentModeration {...shared} {...moderation} contentKinds={kinds.map((value) => ({ value, label: labelOf(labels, value) }))} basePath={`${base}/moderation`} navigation={nav} />\n ) : section === \"polls\" ? (\n <PollManager {...shared} {...polls} languages={model.kinds.languages} basePath={`${base}/polls`} navigation={nav} />\n ) : (\n <StatsDashboard {...shared} kinds={kinds.map((value) => ({ value, label: labelOf(labels, value) }))} />\n )}\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  export { ContentCard, OwnerChip, PostCard, lockLabel, type ContentCardProps, type PostCardProps } from './card.js';
2
2
  export { CardGrid, ContentGrid, ContentHistory, ContentRail, SearchResults, type CardListProps, type ContentRailProps, type LockedCards } from './grid.js';
3
3
  export { SearchBox, type SearchBoxProps } from './search.js';
4
+ export { ReaderSettings, type ReaderSettingsProps } from './reader-settings.js';
4
5
  export { ContentFilterSettings, ReleaseDateIndex, type ContentFilterSettingsProps, type ReleaseDateIndexProps } from './filters.js';
5
6
  export { ContentListing, sortLabel, type ContentListingProps } from './listing.js';
6
7
  export { Paywall, VersionPicker, priceLabel, useVersionMenuItems, type PaywallProps, type VersionMenuOptions, type VersionPickerProps } from './paywall.js';
@@ -0,0 +1,19 @@
1
+ import { ContentKitUiAppearance } from '../../appearance.js';
2
+ import { ContentKitClient } from '../../client/client.js';
3
+ import { ContentKitErrorHandler } from '../../react/context.js';
4
+ export interface ReaderSettingsProps {
5
+ languages: readonly {
6
+ value: string;
7
+ label: string;
8
+ }[];
9
+ /** The current language, controlled by the host. */
10
+ language: string;
11
+ /** The host applies its own route and preference changes. */
12
+ onLanguageChange: (language: string) => void;
13
+ client?: ContentKitClient;
14
+ onError?: ContentKitErrorHandler;
15
+ className?: string;
16
+ appearance?: ContentKitUiAppearance;
17
+ }
18
+ /** One reader-settings dialog for language and the signed-in reader's filters. */
19
+ export declare function ReaderSettings(p: ReaderSettingsProps): import('react').JSX.Element;
@@ -0,0 +1,95 @@
1
+ import { useMessages as e } from "../../i18n/context.js";
2
+ import { AppearanceContext as t, ContentKitUiRoot as n } from "../../scope.js";
3
+ import { ContentKitContext as r } from "../../react/context.js";
4
+ import { Button as i } from "../../ui/button.js";
5
+ import { Dialog as a, DialogContent as o, DialogDescription as s, DialogHeader as c, DialogTitle as l, DialogTrigger as u } from "../../ui/dialog.js";
6
+ import { Label as d } from "../../ui/label.js";
7
+ import { Select as f, SelectContent as p, SelectItem as m, SelectTrigger as h, SelectValue as g } from "../../ui/select.js";
8
+ import { useContentFilters as _ } from "../../react/discovery.js";
9
+ import { ContentFilterSettings as v } from "./filters.js";
10
+ import { useContext as y, useId as b } from "react";
11
+ import { jsx as x, jsxs as S } from "react/jsx-runtime";
12
+ import { Settings01Icon as C } from "@hugeicons/core-free-icons";
13
+ import { HugeiconsIcon as w } from "@hugeicons/react";
14
+ //#region src/components/content/reader-settings.tsx
15
+ function T(_) {
16
+ let { t: v } = e(), T = b(), D = y(r)?.viewer, O = y(t), k = _.appearance ?? O;
17
+ return /* @__PURE__ */ x(t.Provider, {
18
+ value: k,
19
+ children: /* @__PURE__ */ x(n, {
20
+ className: _.className,
21
+ appearance: k,
22
+ "data-ckui": "reader-settings",
23
+ children: /* @__PURE__ */ S(a, { children: [/* @__PURE__ */ S(u, {
24
+ render: /* @__PURE__ */ x(i, {
25
+ type: "button",
26
+ variant: "ghost",
27
+ size: "sm",
28
+ "aria-label": v("readerSettings.title"),
29
+ "data-ckui": "reader-settings-trigger"
30
+ }),
31
+ children: [/* @__PURE__ */ x(w, {
32
+ icon: C,
33
+ strokeWidth: 2,
34
+ className: "size-4",
35
+ "aria-hidden": !0
36
+ }), /* @__PURE__ */ x("span", { children: _.language.toUpperCase() })]
37
+ }), /* @__PURE__ */ S(o, {
38
+ className: "max-h-[calc(100dvh-2rem)] overflow-y-auto",
39
+ children: [
40
+ /* @__PURE__ */ S(c, { children: [/* @__PURE__ */ x(l, { children: v("readerSettings.title") }), /* @__PURE__ */ x(s, {
41
+ className: "sr-only",
42
+ children: v("readerSettings.description")
43
+ })] }),
44
+ /* @__PURE__ */ S("div", {
45
+ className: "grid gap-3",
46
+ children: [/* @__PURE__ */ x(d, {
47
+ htmlFor: `${T}-language`,
48
+ children: v("listing.language")
49
+ }), /* @__PURE__ */ S(f, {
50
+ value: _.language,
51
+ onValueChange: (e) => {
52
+ e && e !== _.language && _.onLanguageChange(e);
53
+ },
54
+ children: [/* @__PURE__ */ x(h, {
55
+ id: `${T}-language`,
56
+ className: "w-full",
57
+ children: /* @__PURE__ */ x(g, { children: _.languages.find((e) => e.value === _.language)?.label ?? _.language })
58
+ }), /* @__PURE__ */ x(p, { children: _.languages.map((e) => /* @__PURE__ */ x(m, {
59
+ value: e.value,
60
+ children: e.label
61
+ }, e.value)) })]
62
+ })]
63
+ }),
64
+ D != null && /* @__PURE__ */ x(E, {
65
+ language: _.language,
66
+ client: _.client,
67
+ onError: _.onError
68
+ })
69
+ ]
70
+ })] })
71
+ })
72
+ });
73
+ }
74
+ function E(t) {
75
+ let { t: n } = e(), r = b(), { filters: i } = _({
76
+ language: t.language,
77
+ client: t.client
78
+ });
79
+ return i?.filters.length === 0 ? null : /* @__PURE__ */ S("section", {
80
+ "aria-labelledby": r,
81
+ className: "grid gap-3",
82
+ children: [/* @__PURE__ */ x("h3", {
83
+ id: r,
84
+ className: "font-medium",
85
+ children: n("readerSettings.filters")
86
+ }), /* @__PURE__ */ x(v, {
87
+ ...t,
88
+ includeDeleted: !1
89
+ })]
90
+ });
91
+ }
92
+ //#endregion
93
+ export { T as ReaderSettings };
94
+
95
+ //# sourceMappingURL=reader-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader-settings.js","names":[],"sources":["../../../src/components/content/reader-settings.tsx"],"sourcesContent":["import { Settings01Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { useContext, useId } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useContentFilters } from \"../../react/discovery.js\";\nimport { AppearanceContext, ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from \"#ckui/ui/dialog\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { ContentFilterSettings } from \"./filters.js\";\n\nexport interface ReaderSettingsProps {\n languages: readonly { value: string; label: string }[];\n /** The current language, controlled by the host. */\n language: string;\n /** The host applies its own route and preference changes. */\n onLanguageChange: (language: string) => void;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** One reader-settings dialog for language and the signed-in reader's filters. */\nexport function ReaderSettings(p: ReaderSettingsProps) {\n const { t } = useMessages();\n const id = useId();\n const viewer = useContext(ContentKitContext)?.viewer;\n const inheritedAppearance = useContext(AppearanceContext);\n const appearance = p.appearance ?? inheritedAppearance;\n return (\n <AppearanceContext.Provider value={appearance}>\n <ContentKitUiRoot className={p.className} appearance={appearance} data-ckui=\"reader-settings\">\n <Dialog>\n <DialogTrigger render={<Button type=\"button\" variant=\"ghost\" size=\"sm\" aria-label={t(\"readerSettings.title\")} data-ckui=\"reader-settings-trigger\" />}>\n <HugeiconsIcon icon={Settings01Icon} strokeWidth={2} className=\"size-4\" aria-hidden />\n <span>{p.language.toUpperCase()}</span>\n </DialogTrigger>\n <DialogContent className=\"max-h-[calc(100dvh-2rem)] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t(\"readerSettings.title\")}</DialogTitle>\n <DialogDescription className=\"sr-only\">{t(\"readerSettings.description\")}</DialogDescription>\n </DialogHeader>\n <div className=\"grid gap-3\">\n <Label htmlFor={`${id}-language`}>{t(\"listing.language\")}</Label>\n <Select value={p.language} onValueChange={(value) => { if (value && value !== p.language) p.onLanguageChange(value); }}>\n <SelectTrigger id={`${id}-language`} className=\"w-full\">\n <SelectValue>{p.languages.find((item) => item.value === p.language)?.label ?? p.language}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {p.languages.map((item) => <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n {viewer != null && <ReaderFilters language={p.language} client={p.client} onError={p.onError} />}\n </DialogContent>\n </Dialog>\n </ContentKitUiRoot>\n </AppearanceContext.Provider>\n );\n}\n\nfunction ReaderFilters(p: Pick<ReaderSettingsProps, \"language\" | \"client\" | \"onError\">) {\n const { t } = useMessages();\n const id = useId();\n const { filters } = useContentFilters({ language: p.language, client: p.client });\n if (filters?.filters.length === 0) return null;\n return (\n <section aria-labelledby={id} className=\"grid gap-3\">\n <h3 id={id} className=\"font-medium\">{t(\"readerSettings.filters\")}</h3>\n <ContentFilterSettings {...p} includeDeleted={false} />\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AA4BA,SAAgB,EAAe,GAAwB;CACrD,IAAM,EAAE,SAAM,EAAY,GACpB,IAAK,EAAM,GACX,IAAS,EAAW,CAAiB,CAAC,EAAE,QACxC,IAAsB,EAAW,CAAiB,GAClD,IAAa,EAAE,cAAc;CACnC,OACE,kBAAC,EAAkB,UAAnB;EAA4B,OAAO;EACjC,UAAA,kBAAC,GAAD;GAAkB,WAAW,EAAE;GAAuB;GAAY,aAAU;GAC1E,UAAA,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAe,QAAQ,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAQ,MAAK;KAAK,cAAY,EAAE,sBAAsB;KAAG,aAAU;IAA2B,CAAA;IAAnJ,UAAA,CACE,kBAAC,GAAD;KAAe,MAAM;KAAgB,aAAa;KAAG,WAAU;KAAS,eAAA;IAAa,CAAA,GACrF,kBAAC,QAAD,EAAA,UAAO,EAAE,SAAS,YAAY,EAAQ,CAAA,CACzB;GACf,CAAA,GAAA,kBAAC,GAAD;IAAe,WAAU;IAAzB,UAAA;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAc,EAAE,sBAAsB,EAAe,CAAA,GACrD,kBAAC,GAAD;MAAmB,WAAU;MAAW,UAAA,EAAE,4BAA4B;KAAqB,CAAA,CAC/E,EAAA,CAAA;KACd,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,GAAD;OAAO,SAAS,GAAG,EAAG;OAAa,UAAA,EAAE,kBAAkB;MAAS,CAAA,GAChE,kBAAC,GAAD;OAAQ,OAAO,EAAE;OAAU,gBAAgB,MAAU;QAAE,AAAI,KAAS,MAAU,EAAE,YAAU,EAAE,iBAAiB,CAAK;OAAG;OAArH,UAAA,CACE,kBAAC,GAAD;QAAe,IAAI,GAAG,EAAG;QAAY,WAAU;QAC7C,UAAA,kBAAC,GAAD,EAAA,UAAc,EAAE,UAAU,MAAM,MAAS,EAAK,UAAU,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAsB,CAAA;OACzF,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAE,UAAU,KAAK,MAAS,kBAAC,GAAD;QAA6B,OAAO,EAAK;QAAQ,UAAA,EAAK;OAAkB,GAAvD,EAAK,KAAkD,CAAC,EACvF,CAAA,CACT;MACL,CAAA,CAAA;;KACJ,KAAU,QAAQ,kBAAC,GAAD;MAAe,UAAU,EAAE;MAAU,QAAQ,EAAE;MAAQ,SAAS,EAAE;KAAU,CAAA;IAClF;GACT,CAAA,CAAA,EAAA,CAAA;EACQ,CAAA;CACQ,CAAA;AAEhC;AAEA,SAAS,EAAc,GAAiE;CACtF,IAAM,EAAE,SAAM,EAAY,GACpB,IAAK,EAAM,GACX,EAAE,eAAY,EAAkB;EAAE,UAAU,EAAE;EAAU,QAAQ,EAAE;CAAO,CAAC;CAEhF,OADI,GAAS,QAAQ,WAAW,IAAU,OAExC,kBAAC,WAAD;EAAS,mBAAiB;EAAI,WAAU;EAAxC,UAAA,CACE,kBAAC,MAAD;GAAQ;GAAI,WAAU;GAAe,UAAA,EAAE,wBAAwB;EAAM,CAAA,GACrE,kBAAC,GAAD;GAAuB,GAAI;GAAG,gBAAgB;EAAQ,CAAA,CAC/C;;AAEb"}
@@ -16,6 +16,8 @@ export interface SearchBoxProps {
16
16
  labels?: Labels;
17
17
  /** The reader's recent searches while the box is empty. Default true. */
18
18
  recent?: boolean;
19
+ /** Header-wide dropdown under the nearest header/banner; default stays inline. */
20
+ presentation?: "inline" | "header";
19
21
  client?: ContentKitClient;
20
22
  className?: string;
21
23
  appearance?: ContentKitUiAppearance;