@openrails/contentkit-ui 0.103.2 → 0.104.0-rc.2
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 +111 -49
- package/dist/client/beacons.d.ts +3 -13
- package/dist/client/beacons.js +8 -46
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +45 -43
- package/dist/client/client.js.map +1 -1
- package/dist/client/content/favorites.d.ts +2 -0
- package/dist/client/content/favorites.js.map +1 -1
- package/dist/client/content/types.d.ts +3 -0
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/contents.d.ts +7 -1
- package/dist/client/contents.js +8 -0
- package/dist/client/contents.js.map +1 -1
- package/dist/client/discovery.d.ts +34 -5
- package/dist/client/discovery.js +23 -2
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/engagement.d.ts +70 -0
- package/dist/client/engagement.js +191 -0
- package/dist/client/engagement.js.map +1 -0
- package/dist/client/generated/routes.d.ts +74 -35
- package/dist/client/generated/routes.js +119 -60
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +88 -85
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/guest-reading-history.d.ts +40 -0
- package/dist/client/guest-reading-history.js +144 -0
- package/dist/client/guest-reading-history.js.map +1 -0
- package/dist/client/index.d.ts +5 -3
- package/dist/client/media/windows.d.ts +2 -0
- package/dist/client/media/windows.js +4 -1
- package/dist/client/media/windows.js.map +1 -1
- package/dist/client/stats.d.ts +4 -20
- package/dist/client/stats.js +0 -11
- package/dist/client/stats.js.map +1 -1
- package/dist/client/versions.d.ts +8 -6
- package/dist/client/versions.js +15 -10
- package/dist/client/versions.js.map +1 -1
- package/dist/client.js +24 -22
- package/dist/components/admin/bulk-drafts.d.ts +17 -0
- package/dist/components/admin/bulk-drafts.js +41 -0
- package/dist/components/admin/bulk-drafts.js.map +1 -0
- package/dist/components/admin/content-admin.d.ts +1 -1
- package/dist/components/admin/content-admin.js.map +1 -1
- package/dist/components/admin/content-manager.d.ts +11 -3
- package/dist/components/admin/content-manager.js +751 -394
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.d.ts +8 -3
- package/dist/components/admin/group-manager.js +218 -146
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/page-notices.d.ts +16 -0
- package/dist/components/admin/page-notices.js +113 -0
- package/dist/components/admin/page-notices.js.map +1 -0
- package/dist/components/admin/page-picker.d.ts +38 -0
- package/dist/components/admin/page-picker.js +159 -0
- package/dist/components/admin/page-picker.js.map +1 -0
- package/dist/components/admin/quick-search.d.ts +14 -0
- package/dist/components/admin/quick-search.js +60 -0
- package/dist/components/admin/quick-search.js.map +1 -0
- package/dist/components/admin/reader-content-editor.js +382 -321
- package/dist/components/admin/reader-content-editor.js.map +1 -1
- package/dist/components/admin/reader-manifest.js +181 -179
- package/dist/components/admin/reader-manifest.js.map +1 -1
- package/dist/components/admin/shell.d.ts +10 -2
- package/dist/components/admin/shell.js +114 -42
- package/dist/components/admin/shell.js.map +1 -1
- package/dist/components/admin/stats-dashboard.d.ts +4 -9
- package/dist/components/admin/stats-dashboard.js +303 -207
- package/dist/components/admin/stats-dashboard.js.map +1 -1
- package/dist/components/admin/upload-queue.d.ts +14 -0
- package/dist/components/admin/upload-queue.js +115 -98
- package/dist/components/admin/upload-queue.js.map +1 -1
- package/dist/components/content/card.d.ts +31 -3
- package/dist/components/content/card.js +324 -158
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/daily-releases.js +144 -190
- package/dist/components/content/daily-releases.js.map +1 -1
- package/dist/components/content/editor-save.js +27 -25
- package/dist/components/content/editor-save.js.map +1 -1
- package/dist/components/content/editors.js +274 -253
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/favorites.d.ts +6 -0
- package/dist/components/content/favorites.js +47 -0
- package/dist/components/content/favorites.js.map +1 -0
- package/dist/components/content/filter-dialog.js +19 -15
- package/dist/components/content/filter-dialog.js.map +1 -1
- package/dist/components/content/filters.d.ts +2 -0
- package/dist/components/content/filters.js +5 -1
- package/dist/components/content/filters.js.map +1 -1
- package/dist/components/content/grid.d.ts +44 -16
- package/dist/components/content/grid.js +308 -270
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/history.d.ts +6 -0
- package/dist/components/content/history.js +111 -0
- package/dist/components/content/history.js.map +1 -0
- package/dist/components/content/index.d.ts +6 -3
- package/dist/components/content/listing.d.ts +14 -3
- package/dist/components/content/listing.js +65 -56
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/offer-fields.js +6 -6
- package/dist/components/content/paged-grid.d.ts +10 -0
- package/dist/components/content/paged-grid.js +116 -0
- package/dist/components/content/paged-grid.js.map +1 -0
- package/dist/components/content/pagination.d.ts +19 -0
- package/dist/components/content/pagination.js +97 -0
- package/dist/components/content/pagination.js.map +1 -0
- package/dist/components/content/paywall.d.ts +9 -0
- package/dist/components/content/paywall.js +27 -3
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/post-list.d.ts +37 -0
- package/dist/components/content/post-list.js +203 -0
- package/dist/components/content/post-list.js.map +1 -0
- package/dist/components/content/reader-settings.d.ts +2 -0
- package/dist/components/content/reader-settings.js +1 -1
- package/dist/components/content/reader-settings.js.map +1 -1
- package/dist/components/content/search.d.ts +11 -4
- package/dist/components/content/search.js +22 -11
- package/dist/components/content/search.js.map +1 -1
- package/dist/components/content/summary-tile.d.ts +14 -0
- package/dist/components/content/summary-tile.js +63 -0
- package/dist/components/content/summary-tile.js.map +1 -0
- package/dist/components/groups/banner.d.ts +6 -2
- package/dist/components/groups/banner.js +79 -61
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.d.ts +12 -2
- package/dist/components/groups/directory.js +168 -105
- package/dist/components/groups/directory.js.map +1 -1
- package/dist/components/groups/editor.js +10 -10
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/entity-chips.d.ts +61 -0
- package/dist/components/groups/entity-chips.js +382 -0
- package/dist/components/groups/entity-chips.js.map +1 -0
- package/dist/components/groups/group-members.d.ts +29 -0
- package/dist/components/groups/group-members.js +474 -0
- package/dist/components/groups/group-members.js.map +1 -0
- package/dist/components/groups/header.js +53 -45
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/index.d.ts +3 -1
- package/dist/components/groups/memberships.d.ts +3 -36
- package/dist/components/groups/memberships.js +105 -480
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/groups/scoped.d.ts +23 -0
- package/dist/components/groups/scoped.js +92 -0
- package/dist/components/groups/scoped.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +5 -0
- package/dist/components/media-folder-editor.js +419 -231
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/sortable-list.d.ts +5 -1
- package/dist/components/sortable-list.js +97 -81
- package/dist/components/sortable-list.js.map +1 -1
- package/dist/components/video-mini-player.d.ts +4 -1
- package/dist/components/video-mini-player.js +77 -71
- package/dist/components/video-mini-player.js.map +1 -1
- package/dist/components/video-player.d.ts +4 -1
- package/dist/components/video-player.js +280 -276
- package/dist/components/video-player.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +41 -34
- package/dist/locales/admin/de.js +80 -47
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +74 -41
- package/dist/locales/admin/en.js +80 -47
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +80 -47
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +80 -47
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +80 -47
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +80 -47
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/de.js +1 -0
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +25 -2
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +24 -1
- package/dist/locales/discovery/en.js +25 -2
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +25 -2
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +25 -2
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +25 -2
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +25 -2
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +119 -44
- package/dist/locales/en.js +1 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +1 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.js +22 -4
- package/dist/locales/groups/de.js.map +1 -1
- package/dist/locales/groups/en.d.ts +20 -2
- package/dist/locales/groups/en.js +22 -4
- package/dist/locales/groups/en.js.map +1 -1
- package/dist/locales/groups/es.js +22 -4
- package/dist/locales/groups/es.js.map +1 -1
- package/dist/locales/groups/ja.js +22 -4
- package/dist/locales/groups/ja.js.map +1 -1
- package/dist/locales/groups/ko.js +22 -4
- package/dist/locales/groups/ko.js.map +1 -1
- package/dist/locales/groups/zh.js +22 -4
- package/dist/locales/groups/zh.js.map +1 -1
- package/dist/locales/ja.js +1 -0
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +1 -0
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +1 -0
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/discovery.d.ts +36 -17
- package/dist/react/discovery.js +305 -221
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/groups.d.ts +19 -3
- package/dist/react/groups.js +49 -22
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +7 -4
- package/dist/react/page-notices.d.ts +13 -0
- package/dist/react/page-notices.js +38 -0
- package/dist/react/page-notices.js.map +1 -0
- package/dist/react/post-reads.d.ts +23 -0
- package/dist/react/post-reads.js +90 -0
- package/dist/react/post-reads.js.map +1 -0
- package/dist/react/remembered-sort.d.ts +5 -0
- package/dist/react/remembered-sort.js +29 -0
- package/dist/react/remembered-sort.js.map +1 -0
- package/dist/react/resources.d.ts +3 -1
- package/dist/react/resources.js +6 -2
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +3 -7
- package/dist/react/stats.js +2 -6
- package/dist/react/stats.js.map +1 -1
- package/dist/react/use-engagement.d.ts +28 -0
- package/dist/react/use-engagement.js +226 -0
- package/dist/react/use-engagement.js.map +1 -0
- package/dist/react/use-resource.d.ts +4 -3
- package/dist/react/use-resource.js +2 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react.js +29 -26
- package/dist/styles.css +1 -1
- package/dist/ui/dialog.d.ts +2 -1
- package/dist/ui/dialog.js +23 -20
- package/dist/ui/dialog.js.map +1 -1
- package/dist/urls/index.d.ts +1 -1
- package/dist/urls.js +2 -2
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/admin/page-review.d.ts +0 -13
- package/dist/components/admin/page-review.js +0 -225
- package/dist/components/admin/page-review.js.map +0 -1
- package/dist/react/page-review.d.ts +0 -14
- package/dist/react/page-review.js +0 -37
- package/dist/react/page-review.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","names":[],"sources":["../../src/react/discovery.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { Beacons, eventId, type Attribution, type BeaconOptions, type ViewSession } from \"../client/beacons.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { MineQuery } from \"../client/content/favorites.js\";\nimport type { AccessMode, ContentQuery, DailyReleasesQuery, HistoryQuery, RailQuery, ReleaseDatesQuery, SearchQuery, TypeaheadQuery } from \"../client/discovery.js\";\nimport { ContentKitError, toContentKitError } from \"../client/errors.js\";\nimport type { Card, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, DateCount, GroupCard, Interaction, InteractionPage, RecentSearch } from \"../client/generated/wire.js\";\nimport { ContentKitContext, useGuarded } from \"./context.js\";\nimport { keyOf, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\nimport { recentSearchLimit } from \"../client/browser-search-history.js\";\n\nconst page = (p: ContentPage) => ({ items: p.contents, next: p.next_cursor ?? null });\nconst NO_SEARCHES: RecentSearch[] = [];\n\n// A new identity even after A → B → A, so late requests cannot write into the new visit.\nfunction useCurrentDiscoveryScope(client: ContentKitClient, scope: string): () => boolean {\n const owner = useMemo(() => ({ client, scope }), [client, scope]);\n const current = useRef<typeof owner | null>(owner);\n useLayoutEffect(() => {\n current.current = owner;\n return () => { current.current = null; };\n }, [owner]);\n return useCallback(() => current.current === owner, [owner]);\n}\n\n/** Titles, names and paths in the provider's language unless the query says otherwise. */\nfunction useDisplay<T extends { display_language?: string }>(q: T | null): T | null {\n const language = useContext(ContentKitContext)?.language;\n return useMemo(() => (q && !q.display_language && language ? { ...q, display_language: language } : q), [q, language]);\n}\n\n/** Contents as cards, a cursor page at a time; null reads nothing. */\nexport function useContents(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): UseList<Card> {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n return useList(store, query ? keyOf(\"cards\", scope, \"list\", query) : null, { type: \"cards\" }, async (cursor, signal) =>\n page(await client.discovery.list({ ...query, cursor: cursor as string | undefined }, signal)),\n );\n}\n\n/**\n * How many contents of a list the reader doesn't open: its filters' count\n * with locked cards less without them (sort and paging aside); null reads\n * nothing.\n */\nexport function useLockedCount(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): { count?: number; loading: boolean } {\n const { client, store, scope } = useContentScope(o.client);\n const filter = useMemo(() => {\n if (!q) return null;\n const { sort: _s, cursor: _c, limit: _l, card_entities: _g, mode: _m, ...f } = q;\n return f;\n }, [q]);\n const query = useDisplay(filter);\n const r = useResource<number>(store, query ? keyOf(\"release-dates\", scope, \"locked\", query) : null, { type: \"release-dates\" }, async (signal) => {\n const count = async (mode: AccessMode) =>\n (await client.discovery.releaseDates({ ...query, mode, by: \"month\", limit: 1000 }, signal)).dates.reduce((n, d) => n + d.count, 0);\n const [all, open] = await Promise.all([count(\"lock\"), count(\"hide\")]);\n return Math.max(0, all - open);\n });\n return { count: r.data, loading: r.loading };\n}\n\n/** Keyword search results as cards; nothing while q.q is empty. */\nexport function useSearch(q: SearchQuery | null, o: { client?: ContentKitClient } = {}): UseList<Card> {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q?.q.trim() ? q : null);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n return useList(store, query ? keyOf(\"cards\", scope, \"search\", query) : null, { type: \"cards\" }, async (cursor, signal) => {\n const out = await client.discovery.search({ ...query!, cursor: cursor as string | undefined }, signal);\n if (!cursor && viewer === null && !signal.aborted && isCurrent()) client.discovery.browserSearches.record(query!.q, out.contents.length);\n return page(out);\n });\n}\n\nexport interface UseRail {\n items: Card[];\n loading: boolean;\n error?: ContentKitError;\n /** The site runs without the signal plane (not_configured): leave the rail out. */\n unavailable: boolean;\n reload: () => void;\n}\n\nfunction useRail(key: string | null, fetch: (signal: AbortSignal) => Promise<ContentPage>, o: { client?: ContentKitClient }): UseRail {\n const { store } = useContentScope(o.client);\n const r = useResource<Card[]>(store, key, { type: \"cards\" }, async (signal) => (await fetch(signal)).contents);\n const unavailable = r.error?.code === \"not_configured\";\n return { items: r.data ?? [], loading: !!key && (r.loading || !r.loaded), error: unavailable ? undefined : r.error, unavailable, reload: r.reload };\n}\n\n/** Contents like one: co-engagement, or the site's configured source. */\nexport function useSimilar(id: string | null | undefined, q: RailQuery = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useRail(id ? keyOf(\"cards\", scope, \"similar\", id, query) : null, (s) => client.discovery.similar(id!, query, s), o);\n}\n\n/** Contents for the signed-in reader; nothing signed out, or when q is null. */\nexport function useRecommendations(q: RailQuery | null = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n return useRail(viewer === null || !query ? null : keyOf(\"cards\", scope, \"recommended\", query), (s) => client.discovery.recommendations(query!, s), o);\n}\n\n/** A release date bucket, keyed by its date. */\nexport type ReleaseDate = DateCount & { id: string };\n\n/** The release date index: per month or day, newest first. */\nexport function useReleaseDates(q: ReleaseDatesQuery = {}, o: { client?: ContentKitClient } = {}): UseList<ReleaseDate> {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useList(store, keyOf(\"release-dates\", scope, query), { type: \"release-dates\" }, async (cursor, signal) => {\n const r = await client.discovery.releaseDates({ ...query, cursor: cursor as string | undefined }, signal);\n return { items: r.dates.map((d) => ({ ...d, id: d.date })), next: r.next_cursor ?? null };\n });\n}\n\nexport interface UseDailyReleases {\n data?: DailyReleases;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/** One complete calendar window, shared by all readers of the same query. */\nexport function useDailyReleases(q: DailyReleasesQuery | null = {}, o: { client?: ContentKitClient } = {}): UseDailyReleases {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const r = useResource<DailyReleases>(store, query ? keyOf(\"daily-releases\", scope, query) : null, { type: \"daily-releases\" }, (signal) => client.discovery.releases(query!, signal));\n return { data: r.data, loading: !!query && (r.loading || !r.loaded), error: r.error, reload: r.reload };\n}\n\nexport interface UseHistory extends UseList<Card> {\n /** Erases the reader's history: of one content item, one kind, or (no argument) everything. */\n forget: (o?: { kind?: string; content_id?: string }) => Promise<void>;\n}\n\n/** What the signed-in reader engaged with, most recent first; nothing signed out, or when q is null. */\nexport function useHistory(q: HistoryQuery | null = {}, o: { client?: ContentKitClient } = {}): UseHistory {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n const guarded = useGuarded();\n const list = useList(store, viewer === null || !query ? null : keyOf(\"history\", scope, query), { type: \"history\" }, async (cursor, signal) =>\n page(await client.discovery.history({ ...query, cursor: cursor as string | undefined }, signal)),\n );\n const forget = useCallback((f: { kind?: string; content_id?: string } = {}) => guarded(() => client.discovery.forgetHistory(f)), [client, guarded]);\n return { ...list, forget };\n}\n\nexport interface UseRecentSearches {\n searches: RecentSearch[];\n loading: boolean;\n error?: ContentKitError;\n /** Clears one query, or every recent search. */\n clear: (query?: string) => Promise<void>;\n}\n\n/** Guest history stays in this browser; account history comes only from the server. enabled false reads nothing yet. */\nexport function useRecentSearches(o: { limit?: number; enabled?: boolean; client?: ContentKitClient } = {}): UseRecentSearches {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const guest = viewer === null;\n const enabled = o.enabled !== false;\n const browser = client.discovery.browserSearches;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_SEARCHES, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_SEARCHES);\n const searches = useMemo(() => local.slice(0, recentSearchLimit(o.limit)), [local, o.limit]);\n const key = !enabled || guest ? null : keyOf(\"searches\", scope, o.limit ?? 10);\n const r = useResource<RecentSearch[]>(store, key, { type: \"searches\" }, async (s) => (await client.discovery.recentSearches({ limit: o.limit }, s)).searches);\n useEffect(() => {\n if (!key) return;\n const reload = () => { if (!store.snapshot(key).loading) store.load(key, true); };\n // Reopening a panel must not leave an already-cached account list stale.\n if (store.snapshot(key).loaded) reload();\n const visible = () => { if (document.visibilityState === \"visible\") reload(); };\n if (typeof window !== \"undefined\") window.addEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.addEventListener(\"visibilitychange\", visible);\n return () => {\n if (typeof window !== \"undefined\") window.removeEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.removeEventListener(\"visibilitychange\", visible);\n };\n }, [key, store]);\n const clear = useCallback(async (query?: string) => {\n if (!isCurrent()) return;\n if (guest) { browser.clear(query); return; }\n await guarded(() => isCurrent() ? client.discovery.clearSearches(query ? { query } : {}) : Promise.resolve());\n }, [browser, client, guest, guarded, isCurrent]);\n return guest\n ? { searches: enabled ? searches : NO_SEARCHES, loading: false, clear }\n : { searches: r.data ?? NO_SEARCHES, loading: !!key && (r.loading || !r.loaded), error: r.error, clear };\n}\n\n/** A favorite or reaction with its content's or group's id. */\nexport type MyInteraction = Interaction & { id: string };\n\nconst interactions = (p: InteractionPage) => ({ items: p.items.map((x) => ({ ...x, id: x.content?.id ?? x.entity?.id ?? \"\" })), next: p.next_cursor ?? null });\n\n/** The signed-in reader's favorites, most recent first: content cards or groups. */\nexport function useMyFavorites(q: MineQuery = {}, o: { client?: ContentKitClient } = {}): UseList<MyInteraction> {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useList(store, viewer === null ? null : keyOf(\"favorites\", scope, query), { type: \"favorites\" }, async (cursor, signal) =>\n interactions(await client.favorites.mine({ ...query, cursor: cursor as string | undefined }, signal)),\n );\n}\n\n/** What the signed-in reader liked (or, with value, disliked), most recent first. */\nexport function useMyReactions(q: MineQuery & { value?: \"like\" | \"dislike\" } = {}, o: { client?: ContentKitClient } = {}): UseList<MyInteraction> {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useList(store, viewer === null ? null : keyOf(\"reactions\", scope, query), { type: \"reactions\" }, async (cursor, signal) =>\n interactions(await client.reactions.mine({ ...query, cursor: cursor as string | undefined }, signal)),\n );\n}\n\nexport interface UseContentFilters {\n filters: ContentFilters | null;\n loading: boolean;\n error?: ContentKitError;\n saving: boolean;\n /** Atomically changes submitted entity choices; other choices are preserved. */\n save: (update: ContentFiltersUpdate) => Promise<ContentFilters>;\n setVisible: (entityId: string, visible: boolean) => Promise<ContentFilters>;\n setIncludeDeleted: (include: boolean) => Promise<ContentFilters>;\n}\n\n/** One current-domain control per entity, shared by all applies_to kinds. */\nexport function useContentFilters(o: { language?: string; client?: ContentKitClient } = {}): UseContentFilters {\n const { client, store, scope, viewer, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const guest = viewer === null;\n const browser = client.preferences.browser;\n const local = useSyncExternalStore(browser.subscribe, browser.snapshot, browser.snapshot);\n const key = keyOf(\"content-filters\", scope, language);\n const previous = useRef<{\n client: ContentKitClient;\n language?: string;\n guest: boolean;\n data?: ContentFilters;\n } | null>(null);\n const initial =\n guest && previous.current?.guest && previous.current.client === client && previous.current.language === language\n ? previous.current.data\n : undefined;\n const r = useResource<ContentFilters>(\n store,\n key,\n { type: \"content-filters\" },\n (signal) => client.discovery.contentFilters(language, signal),\n { initial },\n );\n previous.current = { client, language, guest, data: r.data };\n const applyGuest = useCallback(\n (source: ContentFilters, choices = local): ContentFilters => {\n const values = new Map(choices.filters.map((row) => [row.entity_id, row]));\n return {\n ...source,\n include_deleted: false,\n filters: source.filters.map((row) => {\n const choice = values.get(row.entity.id);\n return { ...row, visible: choice?.visible ?? row.default_visible, overridden: choice?.visible !== undefined };\n }),\n };\n },\n [local],\n );\n const displayed = useMemo(() => (r.data && guest ? applyGuest(r.data) : r.data), [r.data, guest, applyGuest]);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const [inflight, setInflight] = useState(0);\n const current = useRef(displayed);\n current.current = displayed;\n useEffect(() => {\n setInflight(0);\n }, [client, scope]);\n const save = useCallback(\n async (update: ContentFiltersUpdate) => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n if (guest) {\n const source = current.current;\n if (!source) throw new ContentKitError(\"invalid_request\", \"Content filters have not loaded.\");\n const allowed = new Set(source.filters.map((row) => row.entity.id));\n const updates: import(\"../client/browser-reader-preferences.js\").ReaderFilterChoice[] = [];\n const seen = new Set<string>();\n for (const row of update.filters ?? []) {\n if (!allowed.has(row.entity_id) || seen.has(row.entity_id))\n throw new ContentKitError(\"invalid_request\", \"This content filter is not configured or is set twice.\");\n seen.add(row.entity_id);\n if (row.default === true && row.visible === undefined)\n updates.push({ entity_id: row.entity_id, default: true });\n else if (row.default === undefined && typeof row.visible === \"boolean\")\n updates.push({ entity_id: row.entity_id, visible: row.visible });\n else throw new ContentKitError(\"invalid_request\", \"A content filter needs visible or default:true.\");\n }\n client.preferences.setGuestFilters(updates);\n return applyGuest(source, browser.snapshot());\n }\n const submitted = new Set((update.filters ?? []).map((row) => row.entity_id));\n const changesDeleted = typeof update.include_deleted === \"boolean\";\n setInflight((n) => n + 1);\n try {\n const out = await guarded(() => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n return client.discovery.setContentFilters(update, language);\n });\n if (isCurrent()) {\n const rows = new Map(out.filters.map((row) => [row.entity.id, row]));\n // Another control may already have applied a newer response. Merge\n // only this request's choices, never its stale unrelated snapshot.\n store.set<ContentFilters>(key, (previous) => previous ? {\n ...previous,\n filters: previous.filters.flatMap((row) => {\n if (!submitted.has(row.entity.id)) return [row];\n const next = rows.get(row.entity.id);\n return next ? [next] : [];\n }),\n include_deleted: changesDeleted ? out.include_deleted : previous.include_deleted,\n } : out);\n }\n return out;\n } finally {\n setInflight((n) => Math.max(0, n - 1));\n }\n },\n [client, guarded, language, key, store, isCurrent, guest, browser, applyGuest],\n );\n const setVisible = useCallback(\n (entityId: string, visible: boolean) => save({ filters: [{ entity_id: entityId, visible }] }),\n [save],\n );\n const setIncludeDeleted = useCallback((include: boolean) => save({ include_deleted: include }), [save]);\n return {\n filters: displayed ?? null,\n loading: r.loading || !r.loaded,\n error: r.error,\n saving: inflight > 0,\n save,\n setVisible,\n setIncludeDeleted,\n };\n}\n\nexport interface UseTypeahead {\n contents: Card[];\n entities: GroupCard[];\n /** The query the suggestions answer (trimmed). */\n query: string;\n loading: boolean;\n error?: ContentKitError;\n}\n\nconst NONE: Pick<UseTypeahead, \"contents\" | \"entities\"> = { contents: [], entities: [] };\n\n/** Suggestions while the reader types: debounced, the stale ones abandoned. */\nexport function useTypeahead(\n text: string,\n o: Omit<TypeaheadQuery, \"q\"> & { debounce?: number; minLength?: number; client?: ContentKitClient; management?: boolean } = {},\n): UseTypeahead {\n const { client, language, scope: viewerScope } = useContentScope(o.client);\n const { debounce = 150, minLength = 1, client: _own, management = false, ...rest } = o;\n const scope = JSON.stringify([viewerScope, management]);\n const q = text.trim();\n const query = useMemo(() => ({ display_language: language, ...rest, q }), [language, q, JSON.stringify(rest)]); // eslint-disable-line react-hooks/exhaustive-deps\n const [state, setState] = useState<UseTypeahead & { scope: string }>({ ...NONE, query: \"\", loading: false, scope });\n useEffect(() => {\n if (q.length < minLength) {\n setState({ ...NONE, query: \"\", loading: false, scope });\n return;\n }\n setState((s) => ({ ...(s.scope === scope ? s : { ...NONE, query: \"\" }), loading: true, scope }));\n const ctl = new AbortController();\n const timer = setTimeout(() => {\n const request = management\n ? client.entities.manage({ q, kind: query.entity_kinds?.[0], language: query.display_language, limit: query.limit ?? 10 }, ctl.signal)\n .then((page) => ({ contents: [], entities: page.entities }))\n : client.discovery.typeahead(query, ctl.signal);\n request.then(\n (r) => { if (!ctl.signal.aborted) setState({ contents: r.contents, entities: r.entities, query: q, loading: false, scope }); },\n (e) => {\n const error = toContentKitError(e);\n if (!ctl.signal.aborted && error.code !== \"aborted\") setState({ ...NONE, query: q, loading: false, error, scope });\n },\n );\n }, debounce);\n return () => {\n clearTimeout(timer);\n ctl.abort();\n };\n }, [client, query, q, debounce, minLength, management, scope]);\n return state.scope === scope ? state : { ...NONE, query: \"\", loading: q.length >= minLength };\n}\n\nconst beacons = new WeakMap<ContentKitClient, Beacons>();\n\n/** The client's signal and exposure batcher: one per client. */\nexport function beaconsFor(client: ContentKitClient, o?: BeaconOptions): Beacons {\n let b = beacons.get(client);\n if (!b) beacons.set(client, (b = new Beacons(client, o)));\n return b;\n}\n\nexport function useBeacons(o: { client?: ContentKitClient } = {}): Beacons {\n const { client } = useContentScope(o.client);\n return beaconsFor(client);\n}\n\n/** A view of a content (or one version) while it is shown: report its progress as it changes. */\nexport function useViewSignal(content: string | null | undefined, version?: string, o: Attribution & { client?: ContentKitClient } = {}): ViewSession[\"update\"] {\n const { client, scope, viewer, language } = useContentScope(o.client);\n const b = beaconsFor(client);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n // Retire the mutable session whenever its owner or read scope changes.\n const holder = useMemo(() => ({ session: undefined as ViewSession | undefined }), [b, content, version, scope]); // eslint-disable-line react-hooks/exhaustive-deps\n return useCallback((u) => {\n if (!content || !isCurrent() || (viewer !== undefined && client.preferences.identity() !== viewer)) return;\n // Create after the committed provider has configured authentication, not\n // during render while the transport can still belong to the old account.\n holder.session ??= b.view(content, version, { render_id: o.render_id, surface: o.surface, position: o.position, language: o.language ?? language });\n holder.session.update(u);\n }, [b, client, content, version, viewer, language, o.language, o.render_id, o.surface, o.position, holder, isCurrent]);\n}\n\nexport interface ExposureOptions {\n /** Where the list is: \"home\", \"search\", \"similar\". */\n surface: string;\n /** Changes with what the list shows: a new render id. */\n render: string;\n ranker?: string;\n query_id?: string;\n language?: string;\n client?: ContentKitClient;\n}\n\nexport interface UseExposure {\n /** The first bounded segment; click() selects the matching segment for later positions. */\n render_id: string;\n /** A card's ref: reports it shown once at least half of it is in view. */\n track: (content: string, position: number) => (el: Element | null) => void;\n /** Reports a click on the card at position. */\n click: (content: string, position: number) => void;\n}\n\n/** A rendered result list: each page rendered, each card shown, clicks attributed to the render. */\nexport function useExposure(items: readonly { id: string; version_id?: string; version?: { id: string } | null }[], o: ExposureOptions): UseExposure {\n const { client, scope, language } = useContentScope(o.client);\n const b = beaconsFor(client);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const renderId = useMemo(() => eventId(), [o.render, scope]); // eslint-disable-line react-hooks/exhaustive-deps\n const base = useMemo(() => ({ surface: o.surface, ranker: o.ranker, query_id: o.query_id, language: o.language ?? language }), [o.surface, o.ranker, o.query_id, o.language, language]);\n const state = useMemo(() => ({ segments: new Map<number, ExposureSegment>(), pending: new Set<number>(), timer: undefined as ReturnType<typeof setTimeout> | undefined }), [renderId]); // eslint-disable-line react-hooks/exhaustive-deps\n const segmentID = useCallback((index: number) => index === 0 ? renderId : `${renderId}-${index}`, [renderId]);\n const segmentFor = useCallback((index: number) => {\n let segment = state.segments.get(index);\n if (!segment) {\n segment = { rendered: new Map(), visible: new Map(), renderedRevision: 0, visibleRevision: 0 };\n state.segments.set(index, segment);\n }\n return segment;\n }, [state]);\n useEffect(() => {\n if (!isCurrent()) return;\n const changed = new Set<number>();\n for (const [i, item] of items.entries()) {\n const index = Math.floor(i / EXPOSURE_SEGMENT_SIZE), segment = segmentFor(index);\n if (segment.rendered.has(item.id)) continue;\n segment.rendered.set(item.id, { content_id: item.id, version_id: item.version_id ?? item.version?.id, position: i + 1 });\n changed.add(index);\n }\n for (const index of changed) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"rendered\", revision: ++segment.renderedRevision,\n occurred_at: segment.renderedAt ??= new Date().toISOString(), shown: [...segment.rendered.values()] });\n }\n }, [b, base, items, state, segmentFor, segmentID, isCurrent]);\n const observer = useMemo(() => {\n if (typeof IntersectionObserver !== \"function\") return null;\n return new IntersectionObserver((entries) => {\n if (!isCurrent()) return;\n for (const e of entries) {\n if (!e.isIntersecting) continue;\n const el = e.target as HTMLElement, content = el.dataset.exposureContent!;\n const position = Number(el.dataset.exposurePosition), index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const segment = segmentFor(index);\n if (segment.visible.has(content)) continue;\n segment.visible.set(content, segment.rendered.get(content) ?? { content_id: content, position });\n state.pending.add(index);\n }\n if (!state.pending.size) return;\n state.timer ??= setTimeout(() => {\n state.timer = undefined;\n if (!isCurrent()) return;\n for (const index of state.pending) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"visible\", revision: ++segment.visibleRevision,\n occurred_at: segment.visibleAt ??= new Date().toISOString(), shown: [...segment.visible.values()] });\n }\n state.pending.clear();\n }, 300);\n }, { threshold: 0.5 });\n }, [b, base, state, segmentFor, segmentID, isCurrent]);\n useEffect(() => () => { observer?.disconnect(); clearTimeout(state.timer); }, [observer, state]);\n useEffect(() => {\n for (const index of state.segments.keys()) b.beginExposure(segmentID(index));\n return () => { for (const index of state.segments.keys()) b.endExposure(segmentID(index)); };\n }, [b, state, segmentID]);\n const track = useCallback((content: string, position: number) => (el: Element | null) => {\n if (!el || !observer) return;\n (el as HTMLElement).dataset.exposureContent = content;\n (el as HTMLElement).dataset.exposurePosition = String(position);\n observer.observe(el);\n }, [observer]);\n const click = useCallback((content: string, position: number) => {\n if (!isCurrent()) return;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const item = items.find((item) => item.id === content);\n const version = item?.version_id ?? item?.version?.id;\n b.click(content, { render_id: segmentID(index), surface: o.surface, position, version_id: version, language: base.language });\n }, [b, items, segmentID, o.surface, base.language, isCurrent]);\n return { render_id: renderId, track, click };\n}\n\ntype ObservedPlacement = { content_id: string; version_id?: string; position: number };\ntype ExposureSegment = {\n rendered: Map<string, ObservedPlacement>;\n visible: Map<string, ObservedPlacement>;\n renderedRevision: number;\n visibleRevision: number;\n renderedAt?: string;\n visibleAt?: string;\n};\nconst EXPOSURE_SEGMENT_SIZE = 32;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"discovery.js","names":[],"sources":["../../src/react/discovery.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { Beacons, eventId, type BeaconOptions } from \"../client/beacons.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { MineQuery } from \"../client/content/favorites.js\";\nimport type { ContentQuery, DailyReleasesQuery, HistoryQuery, RailQuery, ReleaseDatesQuery, SearchQuery, TypeaheadQuery } from \"../client/discovery.js\";\nimport { ContentKitError, toContentKitError } from \"../client/errors.js\";\nimport type { Card, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, DateCount, GroupCard, Interaction, InteractionPage, RecentSearch, Typeahead } from \"../client/generated/wire.js\";\nimport { ContentKitContext, useGuarded } from \"./context.js\";\nimport { keyOf, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\nimport { guestStanding, type GuestReadingItem } from \"../client/guest-reading-history.js\";\nimport { recentSearchLimit } from \"../client/browser-search-history.js\";\n\nconst page = (p: ContentPage) => ({ items: p.contents, next: p.next_cursor ?? null, metadata: p.summary });\nexport interface UseContents extends UseList<Card, ContentPage[\"summary\"]> { summary?: ContentPage[\"summary\"] }\nconst NO_SEARCHES: RecentSearch[] = [];\nconst NO_READING: readonly GuestReadingItem[] = Object.freeze([]);\n\n// A new identity even after A → B → A, so late requests cannot write into the new visit.\nfunction useCurrentDiscoveryScope(client: ContentKitClient, scope: string): () => boolean {\n const owner = useMemo(() => ({ client, scope }), [client, scope]);\n const current = useRef<typeof owner | null>(owner);\n useLayoutEffect(() => {\n current.current = owner;\n return () => { current.current = null; };\n }, [owner]);\n return useCallback(() => current.current === owner, [owner]);\n}\n\n/** Titles, names and paths in the provider's language unless the query says otherwise. */\nfunction useDisplay<T extends { display_language?: string }>(q: T | null): T | null {\n const language = useContext(ContentKitContext)?.language;\n return useMemo(() => (q && !q.display_language && language ? { ...q, display_language: language } : q), [q, language]);\n}\n\n/** Contents as cards, a cursor page at a time; null reads nothing. */\nexport function useContents(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): UseContents {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const list = useList(store, query ? keyOf(\"cards\", scope, \"list\", query) : null, { type: \"cards\" }, async (cursor, signal) =>\n page(await client.discovery.list({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\n/** One numbered page of a list or search: its cards and the selection's summary (total included). */\nexport interface UseContentsPage {\n items: Card[];\n summary?: ContentPage[\"summary\"];\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\nconst NO_CARDS: Card[] = [];\n\nfunction useNumbered(key: string | null, fetch: (signal: AbortSignal) => Promise<ContentPage>, o: { client?: ContentKitClient }): UseContentsPage {\n const { store } = useContentScope(o.client);\n const r = useResource<ContentPage>(store, key, { type: \"cards\" }, fetch);\n return { items: r.data?.contents ?? NO_CARDS, summary: r.data?.summary, loading: r.loading || (!!key && !r.loaded), error: r.error, reload: r.reload };\n}\n\n/** Page `page` (from 1) of a list, with its summary; null reads nothing. */\nexport function useContentsPage(q: ContentQuery | null, page: number, o: { client?: ContentKitClient } = {}): UseContentsPage {\n const { client, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const n = Math.max(1, Math.floor(page));\n return useNumbered(query ? keyOf(\"cards\", scope, \"list-page\", query, n) : null, (signal) => client.discovery.list({ ...query!, cursor: undefined, page: n, summary: query!.summary ?? true }, signal), o);\n}\n\n/** Page `page` (from 1) of a search, with its summary; nothing until the query has text. */\nexport function useSearchPage(q: SearchQuery | null, page: number, o: { client?: ContentKitClient } = {}): UseContentsPage {\n const { client, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q?.q.trim() ? q : null);\n const n = Math.max(1, Math.floor(page));\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n return useNumbered(\n query ? keyOf(\"cards\", scope, \"search-page\", query, n) : null,\n async (signal) => {\n const out = await client.discovery.search({ ...query!, cursor: undefined, page: n, summary: query!.summary ?? true }, signal);\n if (n === 1 && viewer === null && !signal.aborted && isCurrent()) client.discovery.browserSearches.record(query!.q, out.contents.length);\n return out;\n },\n o,\n );\n}\n\n/** Locked contents in the same full selection, including its activity window. */\nexport function useLockedCount(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): { count?: number; loading: boolean } {\n const { client, store, scope } = useContentScope(o.client);\n const filter = useMemo(() => {\n if (!q) return null;\n const { cursor: _cursor, ...rest } = q;\n return { ...rest, mode: \"lock\" as const, limit: 1, summary: true };\n }, [q]);\n const query = useDisplay(filter);\n const r = useResource<number>(store, query ? keyOf(\"cards\", scope, \"locked-summary\", query) : null, { type: \"cards\" }, async (signal) => {\n const out = await client.discovery.list(query!, signal);\n return out.summary?.locked_count ?? 0;\n });\n return { count: r.data, loading: r.loading };\n}\n\n/** Keyword search results as cards; nothing while q.q is empty. */\nexport function useSearch(q: SearchQuery | null, o: { client?: ContentKitClient } = {}): UseContents {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q?.q.trim() ? q : null);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const list = useList(store, query ? keyOf(\"cards\", scope, \"search\", query) : null, { type: \"cards\" }, async (cursor, signal) => {\n const out = await client.discovery.search({ ...query!, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal);\n if (!cursor && viewer === null && !signal.aborted && isCurrent()) client.discovery.browserSearches.record(query!.q, out.contents.length);\n return page(out);\n });\n return { ...list, summary: list.metadata };\n}\n\nexport interface UseRail {\n items: Card[];\n summary?: ContentPage[\"summary\"];\n loading: boolean;\n error?: ContentKitError;\n /** The site runs without the signal plane (not_configured): leave the rail out. */\n unavailable: boolean;\n reload: () => void;\n}\n\nfunction useRail(key: string | null, fetch: (signal: AbortSignal) => Promise<ContentPage>, o: { client?: ContentKitClient }): UseRail {\n const { store } = useContentScope(o.client);\n const r = useResource<ContentPage>(store, key, { type: \"cards\" }, fetch);\n const unavailable = r.error?.code === \"not_configured\";\n return { items: r.data?.contents ?? [], summary: r.data?.summary, loading: !!key && (r.loading || !r.loaded), error: unavailable ? undefined : r.error, unavailable, reload: r.reload };\n}\n\n/** Contents like one: co-engagement, or the site's configured source. */\nexport function useSimilar(id: string | null | undefined, q: RailQuery = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useRail(id ? keyOf(\"cards\", scope, \"similar\", id, query) : null, (s) => client.discovery.similar(id!, query, s), o);\n}\n\n/** Contents for the signed-in reader; nothing signed out, or when q is null. */\nexport function useRecommendations(q: RailQuery | null = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n return useRail(viewer === null || !query ? null : keyOf(\"cards\", scope, \"recommended\", query), (s) => client.discovery.recommendations(query!, s), o);\n}\n\n/** A release date bucket, keyed by its date. */\nexport type ReleaseDate = DateCount & { id: string };\n\n/** The release date index: per month or day, newest first. */\nexport function useReleaseDates(q: ReleaseDatesQuery = {}, o: { client?: ContentKitClient } = {}): UseList<ReleaseDate> {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useList(store, keyOf(\"release-dates\", scope, query), { type: \"release-dates\" }, async (cursor, signal) => {\n const r = await client.discovery.releaseDates({ ...query, cursor: cursor as string | undefined }, signal);\n return { items: r.dates.map((d) => ({ ...d, id: d.date })), next: r.next_cursor ?? null };\n });\n}\n\nexport interface UseDailyReleases {\n data?: DailyReleases;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/** One complete calendar window, shared by all readers of the same query. */\nexport function useDailyReleases(q: DailyReleasesQuery | null = {}, o: { client?: ContentKitClient } = {}): UseDailyReleases {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const r = useResource<DailyReleases>(store, query ? keyOf(\"daily-releases\", scope, query) : null, { type: \"daily-releases\" }, (signal) => client.discovery.releases(query!, signal));\n return { data: r.data, loading: !!query && (r.loading || !r.loaded), error: r.error, reload: r.reload };\n}\n\nexport interface UseHistory extends UseContents {\n /** A status-filtered guest selection has hidden candidates whose current version facts cannot be inspected. */\n filterSummaryUnknown?: boolean;\n /** Erases the reader's history: of one content item, one kind, or (no argument) everything. */\n forget: (o?: { kind?: string; content_id?: string }) => Promise<void>;\n}\n\n/** Account history is authoritative; signed-out reading stays in this browser across tabs. */\nexport function useHistory(q: HistoryQuery | null = {}, o: { client?: ContentKitClient } = {}): UseHistory {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n const guarded = useGuarded();\n const guest = viewer === null;\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const browser = client.guestHistory;\n const enabled = query !== null;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_READING, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_READING);\n const selected = useMemo(() => local.filter(row => !query?.kind || row.kind === query.kind).slice(0, 100), [local, query?.kind]);\n const localRevision = guest ? selected.map(row => [row.id, row.at, row.checkpoints.map(checkpoint => [checkpoint.visit_id, checkpoint.segment_id, checkpoint.revision])]) : undefined;\n const list = useList(store, !query || viewer === undefined ? null : keyOf(\"history\", scope, query, localRevision), { type: \"history\" }, async (cursor, signal) => {\n if (!guest) return page(await client.discovery.history({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal));\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const limit = Math.max(1, Math.min(100, query?.limit ?? 50));\n const batch = selected.slice(offset, offset + limit);\n if (!batch.length) return { items: [], next: null };\n // Public hydration enforces current hard-domain rules, access and optional preferences.\n const out = await client.discovery.list({ ids: (query?.summary && !cursor ? selected : batch).map(row => row.id), summary: !cursor ? query?.summary : undefined, kind: query?.kind, language: query?.language,\n display_language: query?.display_language, mode: query?.mode, card_entities: query?.card_entities, limit: 100 }, signal);\n const cards = new Map(out.contents.map(card => [card.id, card]));\n const items = batch.flatMap(row => {\n const card = cards.get(row.id); if (!card) return [];\n const viewer = guestStanding(card, row);\n if (query?.status === \"seen\" && !viewer.seen || query?.status === \"in_progress\" && (!viewer.seen || viewer.completed) || query?.status === \"completed\" && !viewer.completed) return [];\n return [{ ...card, viewer }];\n });\n return { items, next: offset + batch.length < selected.length ? offset + batch.length : null, metadata: out.summary };\n });\n const forget = useCallback((filter: { kind?: string; content_id?: string } = {}) => {\n if (!isCurrent()) return Promise.resolve();\n if (guest) { browser.clear(filter); return Promise.resolve(); }\n return guarded(() => client.discovery.forgetHistory(filter));\n }, [browser, client, guest, guarded, isCurrent]);\n const uncertain = guest && !!query?.status;\n return { ...list, summary: uncertain ? undefined : list.metadata, filterSummaryUnknown: uncertain && (list.metadata?.filtered_count ?? 0) > 0, forget };\n}\n\nexport interface UseRecentSearches {\n searches: RecentSearch[];\n loading: boolean;\n error?: ContentKitError;\n /** Clears one query, or every recent search. */\n clear: (query?: string) => Promise<void>;\n}\n\n/** Guest history stays in this browser; account history comes only from the server. enabled false reads nothing yet. */\nexport function useRecentSearches(o: { limit?: number; enabled?: boolean; client?: ContentKitClient } = {}): UseRecentSearches {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const guest = viewer === null;\n const enabled = o.enabled !== false;\n const browser = client.discovery.browserSearches;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_SEARCHES, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_SEARCHES);\n const searches = useMemo(() => local.slice(0, recentSearchLimit(o.limit)), [local, o.limit]);\n const key = !enabled || guest ? null : keyOf(\"searches\", scope, o.limit ?? 10);\n const r = useResource<RecentSearch[]>(store, key, { type: \"searches\" }, async (s) => (await client.discovery.recentSearches({ limit: o.limit }, s)).searches);\n useEffect(() => {\n if (!key) return;\n const reload = () => { if (!store.snapshot(key).loading) store.load(key, true); };\n // Reopening a panel must not leave an already-cached account list stale.\n if (store.snapshot(key).loaded) reload();\n const visible = () => { if (document.visibilityState === \"visible\") reload(); };\n if (typeof window !== \"undefined\") window.addEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.addEventListener(\"visibilitychange\", visible);\n return () => {\n if (typeof window !== \"undefined\") window.removeEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.removeEventListener(\"visibilitychange\", visible);\n };\n }, [key, store]);\n const clear = useCallback(async (query?: string) => {\n if (!isCurrent()) return;\n if (guest) { browser.clear(query); return; }\n await guarded(() => isCurrent() ? client.discovery.clearSearches(query ? { query } : {}) : Promise.resolve());\n }, [browser, client, guest, guarded, isCurrent]);\n return guest\n ? { searches: enabled ? searches : NO_SEARCHES, loading: false, clear }\n : { searches: r.data ?? NO_SEARCHES, loading: !!key && (r.loading || !r.loaded), error: r.error, clear };\n}\n\n/** A favorite or reaction with its content's or group's id. */\nexport type MyInteraction = Interaction & { id: string };\n\nconst interactions = (p: InteractionPage) => ({ items: p.items.map((x) => ({ ...x, id: x.content?.id ?? x.entity?.id ?? \"\" })), next: p.next_cursor ?? null, metadata: p.summary });\n\nexport interface UseInteractions extends UseList<MyInteraction, InteractionPage[\"summary\"]> { summary?: InteractionPage[\"summary\"] }\n\n/** The signed-in reader's favorites, most recent first: content cards or groups. */\nexport function useMyFavorites(q: MineQuery = {}, o: { client?: ContentKitClient } = {}): UseInteractions {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n const list = useList(store, viewer === null ? null : keyOf(\"favorites\", scope, query), { type: \"favorites\" }, async (cursor, signal) =>\n interactions(await client.favorites.mine({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\n/** What the signed-in reader liked (or, with value, disliked), most recent first. */\nexport function useMyReactions(q: MineQuery & { value?: \"like\" | \"dislike\" } = {}, o: { client?: ContentKitClient } = {}): UseInteractions {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n const list = useList(store, viewer === null ? null : keyOf(\"reactions\", scope, query), { type: \"reactions\" }, async (cursor, signal) =>\n interactions(await client.reactions.mine({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\nexport interface UseContentFilters {\n filters: ContentFilters | null;\n loading: boolean;\n error?: ContentKitError;\n saving: boolean;\n /** Atomically changes submitted entity choices; other choices are preserved. */\n save: (update: ContentFiltersUpdate) => Promise<ContentFilters>;\n setVisible: (entityId: string, visible: boolean) => Promise<ContentFilters>;\n setIncludeDeleted: (include: boolean) => Promise<ContentFilters>;\n}\n\n/** One current-domain control per entity, shared by all applies_to kinds. */\nexport function useContentFilters(o: { language?: string; client?: ContentKitClient } = {}): UseContentFilters {\n const { client, store, scope, viewer, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const guest = viewer === null;\n const browser = client.preferences.browser;\n const local = useSyncExternalStore(browser.subscribe, browser.snapshot, browser.snapshot);\n const key = keyOf(\"content-filters\", scope, language);\n const previous = useRef<{\n client: ContentKitClient;\n language?: string;\n guest: boolean;\n data?: ContentFilters;\n } | null>(null);\n const initial =\n guest && previous.current?.guest && previous.current.client === client && previous.current.language === language\n ? previous.current.data\n : undefined;\n const r = useResource<ContentFilters>(\n store,\n key,\n { type: \"content-filters\" },\n (signal) => client.discovery.contentFilters(language, signal),\n { initial },\n );\n previous.current = { client, language, guest, data: r.data };\n const applyGuest = useCallback(\n (source: ContentFilters, choices = local): ContentFilters => {\n const values = new Map(choices.filters.map((row) => [row.entity_id, row]));\n return {\n ...source,\n include_deleted: false,\n filters: source.filters.map((row) => {\n const choice = values.get(row.entity.id);\n return { ...row, visible: choice?.visible ?? row.default_visible, overridden: choice?.visible !== undefined };\n }),\n };\n },\n [local],\n );\n const displayed = useMemo(() => (r.data && guest ? applyGuest(r.data) : r.data), [r.data, guest, applyGuest]);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const [inflight, setInflight] = useState(0);\n const current = useRef(displayed);\n current.current = displayed;\n useEffect(() => {\n setInflight(0);\n }, [client, scope]);\n const save = useCallback(\n async (update: ContentFiltersUpdate) => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n if (guest) {\n const source = current.current;\n if (!source) throw new ContentKitError(\"invalid_request\", \"Content filters have not loaded.\");\n const allowed = new Set(source.filters.map((row) => row.entity.id));\n const updates: import(\"../client/browser-reader-preferences.js\").ReaderFilterChoice[] = [];\n const seen = new Set<string>();\n for (const row of update.filters ?? []) {\n if (!allowed.has(row.entity_id) || seen.has(row.entity_id))\n throw new ContentKitError(\"invalid_request\", \"This content filter is not configured or is set twice.\");\n seen.add(row.entity_id);\n if (row.default === true && row.visible === undefined)\n updates.push({ entity_id: row.entity_id, default: true });\n else if (row.default === undefined && typeof row.visible === \"boolean\")\n updates.push({ entity_id: row.entity_id, visible: row.visible });\n else throw new ContentKitError(\"invalid_request\", \"A content filter needs visible or default:true.\");\n }\n client.preferences.setGuestFilters(updates);\n return applyGuest(source, browser.snapshot());\n }\n const submitted = new Set((update.filters ?? []).map((row) => row.entity_id));\n const changesDeleted = typeof update.include_deleted === \"boolean\";\n setInflight((n) => n + 1);\n try {\n const out = await guarded(() => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n return client.discovery.setContentFilters(update, language);\n });\n if (isCurrent()) {\n const rows = new Map(out.filters.map((row) => [row.entity.id, row]));\n // Another control may already have applied a newer response. Merge\n // only this request's choices, never its stale unrelated snapshot.\n store.set<ContentFilters>(key, (previous) => previous ? {\n ...previous,\n filters: previous.filters.flatMap((row) => {\n if (!submitted.has(row.entity.id)) return [row];\n const next = rows.get(row.entity.id);\n return next ? [next] : [];\n }),\n include_deleted: changesDeleted ? out.include_deleted : previous.include_deleted,\n } : out);\n }\n return out;\n } finally {\n setInflight((n) => Math.max(0, n - 1));\n }\n },\n [client, guarded, language, key, store, isCurrent, guest, browser, applyGuest],\n );\n const setVisible = useCallback(\n (entityId: string, visible: boolean) => save({ filters: [{ entity_id: entityId, visible }] }),\n [save],\n );\n const setIncludeDeleted = useCallback((include: boolean) => save({ include_deleted: include }), [save]);\n return {\n filters: displayed ?? null,\n loading: r.loading || !r.loaded,\n error: r.error,\n saving: inflight > 0,\n save,\n setVisible,\n setIncludeDeleted,\n };\n}\n\nexport interface UseTypeahead {\n contents: Card[];\n entities: GroupCard[];\n /** The query the suggestions answer (trimmed). */\n query: string;\n loading: boolean;\n error?: ContentKitError;\n}\n\nconst NONE: Pick<UseTypeahead, \"contents\" | \"entities\"> = { contents: [], entities: [] };\n\n/** Suggestions while the reader types: debounced, the stale ones abandoned. */\nexport function useTypeahead(\n text: string,\n o: Omit<TypeaheadQuery, \"q\"> & { debounce?: number; minLength?: number; client?: ContentKitClient; management?: boolean; request?: (query: TypeaheadQuery, signal: AbortSignal) => Promise<Typeahead> } = {},\n): UseTypeahead {\n const { client, language, scope: viewerScope } = useContentScope(o.client);\n const { debounce = 150, minLength = 1, client: _own, management = false, request, ...rest } = o;\n const scope = useMemo(() => ({ viewerScope, management, request }), [viewerScope, management, request]);\n const q = text.trim();\n const query = useMemo(() => ({ display_language: language, ...rest, q }), [language, q, JSON.stringify(rest)]); // eslint-disable-line react-hooks/exhaustive-deps\n const [state, setState] = useState<UseTypeahead & { scope: typeof scope }>({ ...NONE, query: \"\", loading: false, scope });\n useEffect(() => {\n if (q.length < minLength) {\n setState({ ...NONE, query: \"\", loading: false, scope });\n return;\n }\n setState((s) => ({ ...(s.scope === scope ? s : { ...NONE, query: \"\" }), loading: true, scope }));\n const ctl = new AbortController();\n const timer = setTimeout(() => {\n const pending = request ? request(query, ctl.signal) : management\n ? client.entities.manage({ q, kind: query.entity_kinds?.[0], language: query.display_language, limit: query.limit ?? 10 }, ctl.signal)\n .then((page) => ({ contents: [], entities: page.entities }))\n : client.discovery.typeahead(query, ctl.signal);\n pending.then(\n (r) => { if (!ctl.signal.aborted) setState({ contents: r.contents, entities: r.entities, query: q, loading: false, scope }); },\n (e) => {\n const error = toContentKitError(e);\n if (!ctl.signal.aborted && error.code !== \"aborted\") setState({ ...NONE, query: q, loading: false, error, scope });\n },\n );\n }, debounce);\n return () => {\n clearTimeout(timer);\n ctl.abort();\n };\n }, [client, query, q, debounce, minLength, management, request, scope]);\n return state.scope === scope ? state : { ...NONE, query: \"\", loading: q.length >= minLength };\n}\n\nconst beacons = new WeakMap<ContentKitClient, Beacons>();\n\n/** The client's signal and exposure batcher: one per client. */\nexport function beaconsFor(client: ContentKitClient, o?: BeaconOptions): Beacons {\n let b = beacons.get(client);\n if (!b) beacons.set(client, (b = new Beacons(client, o)));\n return b;\n}\n\nexport function useBeacons(o: { client?: ContentKitClient } = {}): Beacons {\n const { client } = useContentScope(o.client);\n return beaconsFor(client);\n}\n\nexport interface ExposureOptions {\n /** Where the list is: \"home\", \"search\", \"similar\". */\n surface: string;\n /** Changes with what the list shows: a new render id. */\n render: string;\n ranker?: string;\n query_id?: string;\n language?: string;\n client?: ContentKitClient;\n}\n\nexport interface UseExposure {\n /** The first bounded segment; click() selects the matching segment for later positions. */\n render_id: string;\n /** A card's ref: reports it shown once at least half of it is in view. */\n track: (content: string, position: number) => (el: Element | null) => void;\n /** Reports a click on the card at position. */\n click: (content: string, position: number) => void;\n}\n\n/** A rendered result list: each page rendered, each card shown, clicks attributed to the render. */\nexport function useExposure(items: readonly { id: string; position?: number; version_id?: string; version?: { id: string } | null }[], o: ExposureOptions): UseExposure {\n const { client, scope, language } = useContentScope(o.client);\n const b = beaconsFor(client);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const renderId = useMemo(() => eventId(), [o.render, scope]); // eslint-disable-line react-hooks/exhaustive-deps\n const base = useMemo(() => ({ surface: o.surface, ranker: o.ranker, query_id: o.query_id, language: o.language ?? language }), [o.surface, o.ranker, o.query_id, o.language, language]);\n const state = useMemo(() => ({ segments: new Map<number, ExposureSegment>(), pending: new Set<number>(), timer: undefined as ReturnType<typeof setTimeout> | undefined }), [renderId]); // eslint-disable-line react-hooks/exhaustive-deps\n const segmentID = useCallback((index: number) => index === 0 ? renderId : `${renderId}-${index}`, [renderId]);\n const segmentFor = useCallback((index: number) => {\n let segment = state.segments.get(index);\n if (!segment) {\n segment = { rendered: new Map(), visible: new Map(), renderedRevision: 0, visibleRevision: 0 };\n state.segments.set(index, segment);\n }\n return segment;\n }, [state]);\n useEffect(() => {\n if (!isCurrent()) return;\n const changed = new Set<number>();\n for (const [i, item] of items.entries()) {\n const supplied = item.position;\n const position = supplied !== undefined && Number.isSafeInteger(supplied) && supplied > 0 ? supplied : i + 1;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE), segment = segmentFor(index);\n if (segment.rendered.has(item.id)) continue;\n segment.rendered.set(item.id, { content_id: item.id, version_id: item.version_id ?? item.version?.id, position });\n changed.add(index);\n }\n for (const index of changed) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"rendered\", revision: ++segment.renderedRevision,\n occurred_at: segment.renderedAt ??= new Date().toISOString(), shown: [...segment.rendered.values()] });\n }\n }, [b, base, items, state, segmentFor, segmentID, isCurrent]);\n const observer = useMemo(() => {\n if (typeof IntersectionObserver !== \"function\") return null;\n return new IntersectionObserver((entries) => {\n if (!isCurrent()) return;\n for (const e of entries) {\n if (!e.isIntersecting) continue;\n const el = e.target as HTMLElement, content = el.dataset.exposureContent!;\n const position = Number(el.dataset.exposurePosition), index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const segment = segmentFor(index);\n if (segment.visible.has(content)) continue;\n segment.visible.set(content, segment.rendered.get(content) ?? { content_id: content, position });\n state.pending.add(index);\n }\n if (!state.pending.size) return;\n state.timer ??= setTimeout(() => {\n state.timer = undefined;\n if (!isCurrent()) return;\n for (const index of state.pending) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"visible\", revision: ++segment.visibleRevision,\n occurred_at: segment.visibleAt ??= new Date().toISOString(), shown: [...segment.visible.values()] });\n }\n state.pending.clear();\n }, 300);\n }, { threshold: 0.5 });\n }, [b, base, state, segmentFor, segmentID, isCurrent]);\n useEffect(() => () => { observer?.disconnect(); clearTimeout(state.timer); }, [observer, state]);\n useEffect(() => {\n for (const index of state.segments.keys()) b.beginExposure(segmentID(index));\n return () => { for (const index of state.segments.keys()) b.endExposure(segmentID(index)); };\n }, [b, state, segmentID]);\n const track = useCallback((content: string, position: number) => (el: Element | null) => {\n if (!el || !observer) return;\n (el as HTMLElement).dataset.exposureContent = content;\n (el as HTMLElement).dataset.exposurePosition = String(position);\n observer.observe(el);\n }, [observer]);\n const click = useCallback((content: string, position: number) => {\n if (!isCurrent()) return;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const item = items.find((item) => item.id === content);\n const version = item?.version_id ?? item?.version?.id;\n b.click(content, { render_id: segmentID(index), surface: o.surface, position, version_id: version, language: base.language });\n }, [b, items, segmentID, o.surface, base.language, isCurrent]);\n return { render_id: renderId, track, click };\n}\n\ntype ObservedPlacement = { content_id: string; version_id?: string; position: number };\ntype ExposureSegment = {\n rendered: Map<string, ObservedPlacement>;\n visible: Map<string, ObservedPlacement>;\n renderedRevision: number;\n visibleRevision: number;\n renderedAt?: string;\n visibleAt?: string;\n};\nconst EXPOSURE_SEGMENT_SIZE = 32;\n"],"mappings":"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"}
|
package/dist/react/groups.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ContentKitClient } from '../client/client.js';
|
|
2
2
|
import { ContentKitError } from '../client/errors.js';
|
|
3
|
-
import { ContentMemberships, ContentModel, Edge, EdgeInput, Group, GroupCard, GroupDetail, GroupInput, GroupUpdate, MemberRef, Membership, MergeReport, MyGroup, Name, Edit } from '../client/generated/wire.js';
|
|
3
|
+
import { ContentMemberships, ContentModel, Edge, EdgeInput, Group, GroupCard, GroupDetail, GroupInput, GroupUpdate, MemberRef, Membership, MergeReport, MyGroup, Name, NewEntity, Edit } from '../client/generated/wire.js';
|
|
4
4
|
import { EntityImageSlot, MyEntityQuery } from '../client/entities.js';
|
|
5
5
|
import { UseList } from './use-resource.js';
|
|
6
6
|
export interface UseKinds {
|
|
@@ -32,7 +32,23 @@ export interface GroupFilter {
|
|
|
32
32
|
sort?: GroupSort;
|
|
33
33
|
/** Default 50, at most 200. */
|
|
34
34
|
pageSize?: number;
|
|
35
|
+
/** Management: a canonical name, alias or slug containing this. */
|
|
36
|
+
query?: string;
|
|
37
|
+
/** Management: the deleted, restorable groups instead of active ones. */
|
|
38
|
+
deleted?: boolean;
|
|
35
39
|
}
|
|
40
|
+
/** One numbered page of groups and every matching group's total. */
|
|
41
|
+
export interface UseGroupsPage {
|
|
42
|
+
items: GroupCard[];
|
|
43
|
+
total?: number;
|
|
44
|
+
loading: boolean;
|
|
45
|
+
error?: ContentKitError;
|
|
46
|
+
reload: () => void;
|
|
47
|
+
}
|
|
48
|
+
/** Page `page` (from 1) of active groups with the total. */
|
|
49
|
+
export declare function useGroupsPage(f: GroupFilter, page: number, o?: {
|
|
50
|
+
client?: ContentKitClient;
|
|
51
|
+
}): UseGroupsPage;
|
|
36
52
|
/** Active groups with name, path, cover and count, a cursor page at a time. */
|
|
37
53
|
export declare function useGroups(f?: GroupFilter, o?: {
|
|
38
54
|
client?: ContentKitClient;
|
|
@@ -107,8 +123,8 @@ export interface UseContentGroups {
|
|
|
107
123
|
error?: ContentKitError;
|
|
108
124
|
saving: boolean;
|
|
109
125
|
reload: () => void;
|
|
110
|
-
/** Replaces the content's memberships, its versions' included, in these group kinds (every kind its kind joins when omitted). */
|
|
111
|
-
set: (memberships: Membership[], kinds?: string[]) => Promise<ContentMemberships>;
|
|
126
|
+
/** Replaces the content's memberships, its versions' included, in these group kinds (every kind its kind joins when omitted); create links new names, creating entities of creatable kinds. */
|
|
127
|
+
set: (memberships: Membership[], kinds?: string[], create?: NewEntity[]) => Promise<ContentMemberships>;
|
|
112
128
|
}
|
|
113
129
|
export declare function useContentGroups(contentId: string | null | undefined, o?: {
|
|
114
130
|
language?: string;
|
package/dist/react/groups.js
CHANGED
|
@@ -11,9 +11,31 @@ function u(e = {}) {
|
|
|
11
11
|
reload: o.reload
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
var d = [];
|
|
15
|
+
function f(e, r, a = {}) {
|
|
16
|
+
let { client: o, store: s, scope: c, language: l } = n(a.client), u = e.language ?? l, f = e.pageSize ?? 50, p = Math.max(1, Math.floor(r)), m = i(s, t("groups", c, "page", e.kind, e.parent, e.scope, e.slug, e.letter, u, e.contentKind, e.sort, f, p), { type: "groups" }, (t) => o.entities.list({
|
|
17
|
+
kind: e.kind,
|
|
18
|
+
parent: e.parent,
|
|
19
|
+
scope: e.scope,
|
|
20
|
+
slug: e.slug,
|
|
21
|
+
letter: e.letter,
|
|
22
|
+
language: u,
|
|
23
|
+
content_kind: e.contentKind,
|
|
24
|
+
sort: e.sort,
|
|
25
|
+
page: p,
|
|
26
|
+
limit: f
|
|
27
|
+
}, t));
|
|
28
|
+
return {
|
|
29
|
+
items: m.data?.entities ?? d,
|
|
30
|
+
total: m.data?.total,
|
|
31
|
+
loading: m.loading || !m.loaded,
|
|
32
|
+
error: m.error,
|
|
33
|
+
reload: m.reload
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function p(e = {}, i = {}) {
|
|
15
37
|
let { client: a, store: o, scope: s, language: c } = n(i.client), l = e.language ?? c, u = e.pageSize ?? 50;
|
|
16
|
-
return r(o, t("groups", s, i.management, e.kind, e.parent, e.scope, e.slug, e.letter, l, e.contentKind, e.sort, u), { type: "groups" }, async (t, n) => {
|
|
38
|
+
return r(o, t("groups", s, i.management, e.kind, e.parent, e.scope, e.slug, e.letter, l, e.contentKind, e.sort, u, e.query, e.deleted), { type: "groups" }, async (t, n) => {
|
|
17
39
|
let r = {
|
|
18
40
|
kind: e.kind,
|
|
19
41
|
parent: e.parent,
|
|
@@ -25,14 +47,18 @@ function d(e = {}, i = {}) {
|
|
|
25
47
|
sort: e.sort,
|
|
26
48
|
cursor: t,
|
|
27
49
|
limit: u
|
|
28
|
-
}, o = await (i.management ? a.entities.manage(
|
|
50
|
+
}, o = await (i.management ? a.entities.manage({
|
|
51
|
+
...r,
|
|
52
|
+
q: e.query?.trim() || void 0,
|
|
53
|
+
state: e.deleted ? "deleted" : void 0
|
|
54
|
+
}, n) : a.entities.list(r, n));
|
|
29
55
|
return {
|
|
30
56
|
items: o.entities,
|
|
31
57
|
next: o.next_cursor ?? null
|
|
32
58
|
};
|
|
33
59
|
});
|
|
34
60
|
}
|
|
35
|
-
function
|
|
61
|
+
function m(r, s = {}) {
|
|
36
62
|
let { client: u, store: d, scope: f, language: p } = n(s.client), m = s.language ?? p, [h, g] = l(null), [_, v] = l(null), [y, b] = l(null), x = _ ?? r ?? h;
|
|
37
63
|
o(() => {
|
|
38
64
|
v(null), b(null);
|
|
@@ -133,7 +159,7 @@ function f(r, s = {}) {
|
|
|
133
159
|
}
|
|
134
160
|
};
|
|
135
161
|
}
|
|
136
|
-
function
|
|
162
|
+
function h(e = {}, i = {}) {
|
|
137
163
|
let { client: a, store: o, scope: s, viewer: c, language: l } = n(i.client), { pageSize: u, ...d } = e, f = {
|
|
138
164
|
language: l,
|
|
139
165
|
...d
|
|
@@ -150,13 +176,13 @@ function p(e = {}, i = {}) {
|
|
|
150
176
|
};
|
|
151
177
|
});
|
|
152
178
|
}
|
|
153
|
-
var
|
|
179
|
+
var g = (e) => [
|
|
154
180
|
e.group_id ?? "",
|
|
155
181
|
e.content_id ?? "",
|
|
156
182
|
e.version_id ?? "",
|
|
157
183
|
e.role ?? ""
|
|
158
184
|
].join("|");
|
|
159
|
-
function
|
|
185
|
+
function _(i, o = {}) {
|
|
160
186
|
let { client: s, store: c, scope: u } = n(o.client), d = o.pageSize ?? 50, f = r(c, i ? t("group-members", u, i, d) : null, {
|
|
161
187
|
type: "group-members",
|
|
162
188
|
id: i ?? void 0
|
|
@@ -168,41 +194,42 @@ function h(i, o = {}) {
|
|
|
168
194
|
return {
|
|
169
195
|
items: n.members.map((e) => ({
|
|
170
196
|
...e,
|
|
171
|
-
id:
|
|
197
|
+
id: g(e)
|
|
172
198
|
})),
|
|
173
199
|
next: n.next_cursor ?? null
|
|
174
200
|
};
|
|
175
|
-
}), p = e(), [
|
|
201
|
+
}), p = e(), [m, h] = l(0), _ = a(async (e) => {
|
|
176
202
|
if (!i) throw Error("contentkit-ui: no group");
|
|
177
|
-
|
|
203
|
+
h((e) => e + 1);
|
|
178
204
|
try {
|
|
179
205
|
return (await p(() => e(i))).count;
|
|
180
206
|
} finally {
|
|
181
|
-
|
|
207
|
+
h((e) => e - 1);
|
|
182
208
|
}
|
|
183
209
|
}, [i, p]);
|
|
184
210
|
return {
|
|
185
211
|
...f,
|
|
186
|
-
saving:
|
|
212
|
+
saving: m > 0,
|
|
187
213
|
add: a((e) => _((t) => s.entities.addMembers(t, e)), [s, _]),
|
|
188
214
|
remove: a((e) => _((t) => s.entities.removeMembers(t, e)), [s, _]),
|
|
189
215
|
reorder: a((e) => _((t) => s.entities.reorder(t, e)), [s, _])
|
|
190
216
|
};
|
|
191
217
|
}
|
|
192
|
-
var
|
|
193
|
-
function
|
|
218
|
+
var v = [];
|
|
219
|
+
function y(r, o = {}) {
|
|
194
220
|
let { client: c, store: u, scope: d, language: f } = n(o.client), p = o.language ?? f, m = r ? t("group-memberships", d, r, p) : null, h = i(u, m, {
|
|
195
221
|
type: "group-memberships",
|
|
196
222
|
id: r ?? void 0
|
|
197
|
-
}, (e) => c.entities.ofContent(r, p, e)),
|
|
223
|
+
}, (e) => c.entities.ofContent(r, p, e)), g = e(), [_, y] = l(0), b = a(async (e, t, n) => {
|
|
198
224
|
if (!r) throw Error("contentkit-ui: no content");
|
|
199
225
|
y((e) => e + 1);
|
|
200
226
|
try {
|
|
201
|
-
let
|
|
227
|
+
let i = await g(() => c.entities.setOfContent(r, {
|
|
202
228
|
kinds: t,
|
|
203
|
-
memberships: e
|
|
229
|
+
memberships: e,
|
|
230
|
+
...n?.length ? { create: n } : {}
|
|
204
231
|
}, p));
|
|
205
|
-
return m && u.set(m,
|
|
232
|
+
return m && u.set(m, i), i;
|
|
206
233
|
} finally {
|
|
207
234
|
y((e) => e - 1);
|
|
208
235
|
}
|
|
@@ -210,21 +237,21 @@ function _(r, o = {}) {
|
|
|
210
237
|
c,
|
|
211
238
|
r,
|
|
212
239
|
p,
|
|
213
|
-
|
|
240
|
+
g,
|
|
214
241
|
u,
|
|
215
242
|
m
|
|
216
243
|
]), x = s(() => new Map((h.data?.entities ?? []).map((e) => [e.id, e])), [h.data]);
|
|
217
244
|
return {
|
|
218
|
-
memberships: s(() => h.data?.memberships ??
|
|
245
|
+
memberships: s(() => h.data?.memberships ?? v, [h.data]),
|
|
219
246
|
entities: x,
|
|
220
247
|
loading: !!m && (h.loading || !h.loaded),
|
|
221
248
|
error: h.error,
|
|
222
|
-
saving:
|
|
249
|
+
saving: _ > 0,
|
|
223
250
|
reload: h.reload,
|
|
224
251
|
set: b
|
|
225
252
|
};
|
|
226
253
|
}
|
|
227
254
|
//#endregion
|
|
228
|
-
export {
|
|
255
|
+
export { g as memberId, y as useContentGroups, m as useGroup, _ as useGroupMembers, p as useGroups, f as useGroupsPage, u as useKinds, h as useMyGroups };
|
|
229
256
|
|
|
230
257
|
//# sourceMappingURL=groups.js.map
|
package/dist/react/groups.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groups.js","names":[],"sources":["../../src/react/groups.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type {\n ContentMemberships,\n ContentModel,\n Edge,\n EdgeInput,\n Group,\n GroupCard,\n GroupDetail,\n GroupInput,\n GroupUpdate,\n MemberRef,\n Membership,\n MergeReport,\n MyGroup,\n Name,\n Edit,\n} from \"../client/generated/wire.js\";\nimport type { EntityImageSlot, MyEntityQuery } from \"../client/entities.js\";\nimport { useGuarded } from \"./context.js\";\nimport { keyOf, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\n\nexport interface UseKinds {\n /** null until it loads (or when it fails). */\n kinds: ContentModel | null;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/** The site's content model (GET /v1/kinds): languages, tiers, kinds and entity kinds; one read per client. */\nexport function useKinds(o: { client?: ContentKitClient } = {}): UseKinds {\n const { client, store } = useContentScope(o.client);\n const r = useResource<ContentModel>(store, keyOf(\"kinds\"), { type: \"kinds\" }, (s) => client.kinds(s));\n return { kinds: r.data ?? null, loading: !r.data && (r.loading || !r.loaded), error: r.error, reload: r.reload };\n}\n\nexport type GroupSort = \"name\" | \"count\" | \"newest\";\n\nexport interface GroupFilter {\n kind?: string;\n /** Children of this group. */\n parent?: string;\n /** Groups scoped by this group (characters of a series). */\n scope?: string;\n slug?: string;\n /** Sort names starting with this letter (a-z), or with anything else (\"#\"). */\n letter?: string;\n /** Names, counts and paths in this language; default the provider's. */\n language?: string;\n /** Count contents of this kind only. */\n contentKind?: string;\n /** Default \"name\". */\n sort?: GroupSort;\n /** Default 50, at most 200. */\n pageSize?: number;\n}\n\n/** Active groups with name, path, cover and count, a cursor page at a time. */\nexport function useGroups(f: GroupFilter = {}, o: { client?: ContentKitClient; management?: boolean } = {}): UseList<GroupCard> {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = f.language ?? provided;\n const size = f.pageSize ?? 50;\n return useList(\n store,\n keyOf(\"groups\", scope, o.management, f.kind, f.parent, f.scope, f.slug, f.letter, language, f.contentKind, f.sort, size),\n { type: \"groups\" },\n async (cursor, signal) => {\n const query = { kind: f.kind, parent: f.parent, scope: f.scope, slug: f.slug, letter: f.letter, language, content_kind: f.contentKind, sort: f.sort, cursor: cursor as string | undefined, limit: size };\n const page = await (o.management ? client.entities.manage(query, signal) : client.entities.list(query, signal));\n return { items: page.entities, next: page.next_cursor ?? null };\n },\n );\n}\n\nexport interface UseGroup {\n /** The group as its page shows it; null before create and while loading. A merged group reads as its survivor. */\n group: GroupDetail | null;\n /** What this hook deleted, until restored: reads no longer answer for it. */\n deleted: Group | null;\n loading: boolean;\n error?: ContentKitError;\n /** Writes in flight. */\n saving: boolean;\n reload: () => void;\n /** Creates the group; the hook then shows it. */\n create: (input: GroupInput) => Promise<Group>;\n update: (patch: GroupUpdate) => Promise<Group>;\n remove: () => Promise<Group>;\n restore: () => Promise<Group>;\n /** Replaces (\"set\"), adds or removes names and aliases; a new canonical name demotes the old one to an alias. */\n names: (op: \"set\" | \"add\" | \"remove\", names: Name[]) => Promise<Name[]>;\n edges: (op: \"add\" | \"remove\", edges: EdgeInput[]) => Promise<Edge[]>;\n /** Merges the group into another of its kind; the hook then shows the survivor. */\n merge: (into: string) => Promise<MergeReport>;\n /** Uploads an image (cropped by edit) and selects it as the cover or avatar. */\n uploadImage: (slot: EntityImageSlot, file: Blob & { name?: string }, o?: { wait?: boolean; edit?: Edit }) => Promise<Group>;\n /** Shows the images uploaded here until their renditions exist. */\n previews: Partial<Record<EntityImageSlot, string>>;\n}\n\n/** One group: its page for anyone; create, edit, names, edges, cover, merge, delete and restore for staff (root:groups:write). null creates. */\nexport function useGroup(id: string | null | undefined, o: { language?: string; initial?: GroupDetail; client?: ContentKitClient; management?: boolean } = {}): UseGroup {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const [created, setCreated] = useState<string | null>(null);\n const [merged, setMerged] = useState<string | null>(null);\n const [deleted, setDeleted] = useState<Group | null>(null);\n const gid = merged ?? id ?? created;\n useEffect(() => {\n setMerged(null);\n setDeleted(null);\n }, [id]);\n const key = gid && !deleted ? keyOf(\"group\", scope, o.management, gid, language) : null;\n const r = useResource<GroupDetail>(store, key, { type: \"group\", id: gid ?? undefined }, (s) => o.management ? client.entities.getForManagement(gid!, language, s) : client.entities.get(gid!, language, s), { initial: o.initial });\n const guarded = useGuarded();\n const [inflight, setInflight] = useState(0);\n const run = useCallback(\n async <T>(fn: () => Promise<T>): Promise<T> => {\n setInflight((n) => n + 1);\n try {\n return await guarded(fn);\n } finally {\n setInflight((n) => n - 1);\n }\n },\n [guarded],\n );\n const need = useCallback(() => {\n if (!gid) throw new Error(\"contentkit-ui: create the group first\");\n return gid;\n }, [gid]);\n\n const [previews, setPreviews] = useState<Partial<Record<EntityImageSlot, string>>>({});\n const blobs = useRef<string[]>([]);\n useEffect(() => {\n const urls = blobs.current;\n return () => urls.forEach((u) => URL.revokeObjectURL(u));\n }, []);\n\n const group = r.data ?? null;\n return {\n group: deleted ? null : group,\n deleted,\n loading: !!key && (r.loading || (!r.loaded && o.initial === undefined)),\n error: deleted ? undefined : r.error,\n saving: inflight > 0,\n reload: r.reload,\n create: useCallback(\n (input: GroupInput) =>\n run(async () => {\n const [g] = await client.entities.create([input]);\n setCreated(g!.id);\n return g!;\n }),\n [client, run],\n ),\n update: useCallback((patch: GroupUpdate) => run(() => client.entities.update(need(), patch)), [client, run, need]),\n remove: useCallback(\n () =>\n run(async () => {\n const g = await client.entities.remove(need());\n setDeleted(g);\n return g;\n }),\n [client, run, need],\n ),\n restore: useCallback(\n () =>\n run(async () => {\n const g = await client.entities.update(need(), { state: \"active\" });\n setDeleted(null);\n return g;\n }),\n [client, run, need],\n ),\n names: useCallback((op: \"set\" | \"add\" | \"remove\", names: Name[]) => run(() => client.entities.names(need(), op, names)), [client, run, need]),\n edges: useCallback((op: \"add\" | \"remove\", edges: EdgeInput[]) => run(() => client.entities.edges(need(), op, edges)), [client, run, need]),\n merge: useCallback(\n (into: string) =>\n run(async () => {\n const report = await client.entities.merge(need(), into);\n setMerged(report.into);\n return report;\n }),\n [client, run, need],\n ),\n uploadImage: useCallback(\n (slot: EntityImageSlot, file: Blob & { name?: string }, u: { wait?: boolean; edit?: Edit } = {}) =>\n run(async () => {\n const kind = group?.kind;\n if (!kind) throw new Error(\"contentkit-ui: load the group first\");\n const g = await client.entities.uploadImage({ kind, id: need() }, slot, file, u);\n // A cropped upload's renditions show the crop; until then the file shows uncropped.\n if (typeof URL.createObjectURL === \"function\" && !u.edit) {\n const url = URL.createObjectURL(file);\n blobs.current.push(url);\n setPreviews((p) => ({ ...p, [slot]: url }));\n }\n return g;\n }),\n [client, run, need, group?.kind],\n ),\n previews: { cover: group?.cover?.image ? previews.cover : undefined, avatar: group?.avatar?.image ? previews.avatar : undefined },\n };\n}\n\n/** Groups the signed-in person owns, edits or belongs to, a cursor page at a time; nothing signed out. */\nexport function useMyGroups(q: Omit<MyEntityQuery, \"cursor\" | \"limit\"> & { pageSize?: number } = {}, o: { client?: ContentKitClient } = {}): UseList<MyGroup> {\n const { client, store, scope, viewer, language } = useContentScope(o.client);\n const { pageSize, ...rest } = q;\n const query = { language, ...rest };\n return useList(store, viewer === null ? null : keyOf(\"groups-mine\", scope, query, pageSize), { type: \"groups-mine\" }, async (cursor, signal) => {\n const page = await client.entities.mine({ ...query, cursor: cursor as string | undefined, limit: pageSize }, signal);\n return { items: page.entities, next: page.next_cursor ?? null };\n });\n}\n\n/** A membership with a stable id: (group, content, version, role) is its identity. */\nexport type Member = Membership & { id: string };\n\nexport const memberId = (m: Membership): string => [m.group_id ?? \"\", m.content_id ?? \"\", m.version_id ?? \"\", m.role ?? \"\"].join(\"|\");\n\nexport interface UseGroupMembers extends UseList<Member> {\n saving: boolean;\n /** Adds members, or updates their role's position, window and state. */\n add: (members: Membership[]) => Promise<number>;\n remove: (members: Membership[]) => Promise<number>;\n /** Orders an ordered group: the listed members first, in list order. */\n reorder: (members: MemberRef[]) => Promise<number>;\n}\n\n/** Staff: a group's memberships in member order, with writes. */\nexport function useGroupMembers(id: string | null | undefined, o: { pageSize?: number; client?: ContentKitClient } = {}): UseGroupMembers {\n const { client, store, scope } = useContentScope(o.client);\n const size = o.pageSize ?? 50;\n const list = useList<Member>(store, id ? keyOf(\"group-members\", scope, id, size) : null, { type: \"group-members\", id: id ?? undefined }, async (cursor, signal) => {\n const page = await client.entities.members(id!, { cursor: cursor as string | undefined, limit: size }, signal);\n return { items: page.members.map((m) => ({ ...m, id: memberId(m) })), next: page.next_cursor ?? null };\n });\n const guarded = useGuarded();\n const [inflight, setInflight] = useState(0);\n const write = useCallback(\n async (fn: (gid: string) => Promise<{ count: number }>) => {\n if (!id) throw new Error(\"contentkit-ui: no group\");\n setInflight((n) => n + 1);\n try {\n return (await guarded(() => fn(id))).count;\n } finally {\n setInflight((n) => n - 1);\n }\n },\n [id, guarded],\n );\n return {\n ...list,\n saving: inflight > 0,\n add: useCallback((ms: Membership[]) => write((g) => client.entities.addMembers(g, ms)), [client, write]),\n remove: useCallback((ms: Membership[]) => write((g) => client.entities.removeMembers(g, ms)), [client, write]),\n reorder: useCallback((ms: MemberRef[]) => write((g) => client.entities.reorder(g, ms)), [client, write]),\n };\n}\n\nexport interface UseContentGroups {\n memberships: Membership[];\n /** The groups the memberships name. */\n entities: ReadonlyMap<string, GroupCard>;\n loading: boolean;\n error?: ContentKitError;\n saving: boolean;\n reload: () => void;\n /** Replaces the content's memberships, its versions' included, in these group kinds (every kind its kind joins when omitted). */\n set: (memberships: Membership[], kinds?: string[]) => Promise<ContentMemberships>;\n}\n\n/** Staff: one content's memberships, its versions' included, and their replacement. */\nconst NO_MEMBERSHIPS: Membership[] = [];\n\nexport function useContentGroups(contentId: string | null | undefined, o: { language?: string; client?: ContentKitClient } = {}): UseContentGroups {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const key = contentId ? keyOf(\"group-memberships\", scope, contentId, language) : null;\n const r = useResource<ContentMemberships>(store, key, { type: \"group-memberships\", id: contentId ?? undefined }, (s) => client.entities.ofContent(contentId!, language, s));\n const guarded = useGuarded();\n const [inflight, setInflight] = useState(0);\n const set = useCallback(\n async (memberships: Membership[], kinds?: string[]) => {\n if (!contentId) throw new Error(\"contentkit-ui: no content\");\n setInflight((n) => n + 1);\n try {\n const out = await guarded(() => client.entities.setOfContent(contentId, { kinds, memberships }, language));\n if (key) store.set(key, out);\n return out;\n } finally {\n setInflight((n) => n - 1);\n }\n },\n [client, contentId, language, guarded, store, key],\n );\n const entities = useMemo(() => new Map((r.data?.entities ?? []).map((g) => [g.id, g])), [r.data]);\n // Stable while loading or failed: effects keyed on it must not see a new list every render.\n const memberships = useMemo(() => r.data?.memberships ?? NO_MEMBERSHIPS, [r.data]);\n return {\n memberships,\n entities,\n loading: !!key && (r.loading || !r.loaded),\n error: r.error,\n saving: inflight > 0,\n reload: r.reload,\n set,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"groups.js","names":[],"sources":["../../src/react/groups.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type {\n ContentMemberships,\n ContentModel,\n Edge,\n EdgeInput,\n Group,\n GroupCard,\n GroupDetail,\n GroupInput,\n GroupPage,\n GroupUpdate,\n MemberRef,\n Membership,\n MergeReport,\n MyGroup,\n Name,\n NewEntity,\n Edit,\n} from \"../client/generated/wire.js\";\nimport type { EntityImageSlot, MyEntityQuery } from \"../client/entities.js\";\nimport { useGuarded } from \"./context.js\";\nimport { keyOf, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\n\nexport interface UseKinds {\n /** null until it loads (or when it fails). */\n kinds: ContentModel | null;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/** The site's content model (GET /v1/kinds): languages, tiers, kinds and entity kinds; one read per client. */\nexport function useKinds(o: { client?: ContentKitClient } = {}): UseKinds {\n const { client, store } = useContentScope(o.client);\n const r = useResource<ContentModel>(store, keyOf(\"kinds\"), { type: \"kinds\" }, (s) => client.kinds(s));\n return { kinds: r.data ?? null, loading: !r.data && (r.loading || !r.loaded), error: r.error, reload: r.reload };\n}\n\nexport type GroupSort = \"name\" | \"count\" | \"newest\";\n\nexport interface GroupFilter {\n kind?: string;\n /** Children of this group. */\n parent?: string;\n /** Groups scoped by this group (characters of a series). */\n scope?: string;\n slug?: string;\n /** Sort names starting with this letter (a-z), or with anything else (\"#\"). */\n letter?: string;\n /** Names, counts and paths in this language; default the provider's. */\n language?: string;\n /** Count contents of this kind only. */\n contentKind?: string;\n /** Default \"name\". */\n sort?: GroupSort;\n /** Default 50, at most 200. */\n pageSize?: number;\n /** Management: a canonical name, alias or slug containing this. */\n query?: string;\n /** Management: the deleted, restorable groups instead of active ones. */\n deleted?: boolean;\n}\n\n/** One numbered page of groups and every matching group's total. */\nexport interface UseGroupsPage {\n items: GroupCard[];\n total?: number;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\nconst NO_GROUPS: GroupCard[] = [];\n\n/** Page `page` (from 1) of active groups with the total. */\nexport function useGroupsPage(f: GroupFilter, page: number, o: { client?: ContentKitClient } = {}): UseGroupsPage {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = f.language ?? provided;\n const size = f.pageSize ?? 50;\n const n = Math.max(1, Math.floor(page));\n const r = useResource<GroupPage>(store, keyOf(\"groups\", scope, \"page\", f.kind, f.parent, f.scope, f.slug, f.letter, language, f.contentKind, f.sort, size, n), { type: \"groups\" }, (signal) =>\n client.entities.list({ kind: f.kind, parent: f.parent, scope: f.scope, slug: f.slug, letter: f.letter, language, content_kind: f.contentKind, sort: f.sort, page: n, limit: size }, signal),\n );\n return { items: r.data?.entities ?? NO_GROUPS, total: r.data?.total, loading: r.loading || !r.loaded, error: r.error, reload: r.reload };\n}\n\n/** Active groups with name, path, cover and count, a cursor page at a time. */\nexport function useGroups(f: GroupFilter = {}, o: { client?: ContentKitClient; management?: boolean } = {}): UseList<GroupCard> {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = f.language ?? provided;\n const size = f.pageSize ?? 50;\n return useList(\n store,\n keyOf(\"groups\", scope, o.management, f.kind, f.parent, f.scope, f.slug, f.letter, language, f.contentKind, f.sort, size, f.query, f.deleted),\n { type: \"groups\" },\n async (cursor, signal) => {\n const query = { kind: f.kind, parent: f.parent, scope: f.scope, slug: f.slug, letter: f.letter, language, content_kind: f.contentKind, sort: f.sort, cursor: cursor as string | undefined, limit: size };\n const page = await (o.management\n ? client.entities.manage({ ...query, q: f.query?.trim() || undefined, state: f.deleted ? \"deleted\" : undefined }, signal)\n : client.entities.list(query, signal));\n return { items: page.entities, next: page.next_cursor ?? null };\n },\n );\n}\n\nexport interface UseGroup {\n /** The group as its page shows it; null before create and while loading. A merged group reads as its survivor. */\n group: GroupDetail | null;\n /** What this hook deleted, until restored: reads no longer answer for it. */\n deleted: Group | null;\n loading: boolean;\n error?: ContentKitError;\n /** Writes in flight. */\n saving: boolean;\n reload: () => void;\n /** Creates the group; the hook then shows it. */\n create: (input: GroupInput) => Promise<Group>;\n update: (patch: GroupUpdate) => Promise<Group>;\n remove: () => Promise<Group>;\n restore: () => Promise<Group>;\n /** Replaces (\"set\"), adds or removes names and aliases; a new canonical name demotes the old one to an alias. */\n names: (op: \"set\" | \"add\" | \"remove\", names: Name[]) => Promise<Name[]>;\n edges: (op: \"add\" | \"remove\", edges: EdgeInput[]) => Promise<Edge[]>;\n /** Merges the group into another of its kind; the hook then shows the survivor. */\n merge: (into: string) => Promise<MergeReport>;\n /** Uploads an image (cropped by edit) and selects it as the cover or avatar. */\n uploadImage: (slot: EntityImageSlot, file: Blob & { name?: string }, o?: { wait?: boolean; edit?: Edit }) => Promise<Group>;\n /** Shows the images uploaded here until their renditions exist. */\n previews: Partial<Record<EntityImageSlot, string>>;\n}\n\n/** One group: its page for anyone; create, edit, names, edges, cover, merge, delete and restore for staff (root:groups:write). null creates. */\nexport function useGroup(id: string | null | undefined, o: { language?: string; initial?: GroupDetail; client?: ContentKitClient; management?: boolean } = {}): UseGroup {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const [created, setCreated] = useState<string | null>(null);\n const [merged, setMerged] = useState<string | null>(null);\n const [deleted, setDeleted] = useState<Group | null>(null);\n const gid = merged ?? id ?? created;\n useEffect(() => {\n setMerged(null);\n setDeleted(null);\n }, [id]);\n const key = gid && !deleted ? keyOf(\"group\", scope, o.management, gid, language) : null;\n const r = useResource<GroupDetail>(store, key, { type: \"group\", id: gid ?? undefined }, (s) => o.management ? client.entities.getForManagement(gid!, language, s) : client.entities.get(gid!, language, s), { initial: o.initial });\n const guarded = useGuarded();\n const [inflight, setInflight] = useState(0);\n const run = useCallback(\n async <T>(fn: () => Promise<T>): Promise<T> => {\n setInflight((n) => n + 1);\n try {\n return await guarded(fn);\n } finally {\n setInflight((n) => n - 1);\n }\n },\n [guarded],\n );\n const need = useCallback(() => {\n if (!gid) throw new Error(\"contentkit-ui: create the group first\");\n return gid;\n }, [gid]);\n\n const [previews, setPreviews] = useState<Partial<Record<EntityImageSlot, string>>>({});\n const blobs = useRef<string[]>([]);\n useEffect(() => {\n const urls = blobs.current;\n return () => urls.forEach((u) => URL.revokeObjectURL(u));\n }, []);\n\n const group = r.data ?? null;\n return {\n group: deleted ? null : group,\n deleted,\n loading: !!key && (r.loading || (!r.loaded && o.initial === undefined)),\n error: deleted ? undefined : r.error,\n saving: inflight > 0,\n reload: r.reload,\n create: useCallback(\n (input: GroupInput) =>\n run(async () => {\n const [g] = await client.entities.create([input]);\n setCreated(g!.id);\n return g!;\n }),\n [client, run],\n ),\n update: useCallback((patch: GroupUpdate) => run(() => client.entities.update(need(), patch)), [client, run, need]),\n remove: useCallback(\n () =>\n run(async () => {\n const g = await client.entities.remove(need());\n setDeleted(g);\n return g;\n }),\n [client, run, need],\n ),\n restore: useCallback(\n () =>\n run(async () => {\n const g = await client.entities.update(need(), { state: \"active\" });\n setDeleted(null);\n return g;\n }),\n [client, run, need],\n ),\n names: useCallback((op: \"set\" | \"add\" | \"remove\", names: Name[]) => run(() => client.entities.names(need(), op, names)), [client, run, need]),\n edges: useCallback((op: \"add\" | \"remove\", edges: EdgeInput[]) => run(() => client.entities.edges(need(), op, edges)), [client, run, need]),\n merge: useCallback(\n (into: string) =>\n run(async () => {\n const report = await client.entities.merge(need(), into);\n setMerged(report.into);\n return report;\n }),\n [client, run, need],\n ),\n uploadImage: useCallback(\n (slot: EntityImageSlot, file: Blob & { name?: string }, u: { wait?: boolean; edit?: Edit } = {}) =>\n run(async () => {\n const kind = group?.kind;\n if (!kind) throw new Error(\"contentkit-ui: load the group first\");\n const g = await client.entities.uploadImage({ kind, id: need() }, slot, file, u);\n // A cropped upload's renditions show the crop; until then the file shows uncropped.\n if (typeof URL.createObjectURL === \"function\" && !u.edit) {\n const url = URL.createObjectURL(file);\n blobs.current.push(url);\n setPreviews((p) => ({ ...p, [slot]: url }));\n }\n return g;\n }),\n [client, run, need, group?.kind],\n ),\n previews: { cover: group?.cover?.image ? previews.cover : undefined, avatar: group?.avatar?.image ? previews.avatar : undefined },\n };\n}\n\n/** Groups the signed-in person owns, edits or belongs to, a cursor page at a time; nothing signed out. */\nexport function useMyGroups(q: Omit<MyEntityQuery, \"cursor\" | \"limit\"> & { pageSize?: number } = {}, o: { client?: ContentKitClient } = {}): UseList<MyGroup> {\n const { client, store, scope, viewer, language } = useContentScope(o.client);\n const { pageSize, ...rest } = q;\n const query = { language, ...rest };\n return useList(store, viewer === null ? null : keyOf(\"groups-mine\", scope, query, pageSize), { type: \"groups-mine\" }, async (cursor, signal) => {\n const page = await client.entities.mine({ ...query, cursor: cursor as string | undefined, limit: pageSize }, signal);\n return { items: page.entities, next: page.next_cursor ?? null };\n });\n}\n\n/** A membership with a stable id: (group, content, version, role) is its identity. */\nexport type Member = Membership & { id: string };\n\nexport const memberId = (m: Membership): string => [m.group_id ?? \"\", m.content_id ?? \"\", m.version_id ?? \"\", m.role ?? \"\"].join(\"|\");\n\nexport interface UseGroupMembers extends UseList<Member> {\n saving: boolean;\n /** Adds members, or updates their role's position, window and state. */\n add: (members: Membership[]) => Promise<number>;\n remove: (members: Membership[]) => Promise<number>;\n /** Orders an ordered group: the listed members first, in list order. */\n reorder: (members: MemberRef[]) => Promise<number>;\n}\n\n/** Staff: a group's memberships in member order, with writes. */\nexport function useGroupMembers(id: string | null | undefined, o: { pageSize?: number; client?: ContentKitClient } = {}): UseGroupMembers {\n const { client, store, scope } = useContentScope(o.client);\n const size = o.pageSize ?? 50;\n const list = useList<Member>(store, id ? keyOf(\"group-members\", scope, id, size) : null, { type: \"group-members\", id: id ?? undefined }, async (cursor, signal) => {\n const page = await client.entities.members(id!, { cursor: cursor as string | undefined, limit: size }, signal);\n return { items: page.members.map((m) => ({ ...m, id: memberId(m) })), next: page.next_cursor ?? null };\n });\n const guarded = useGuarded();\n const [inflight, setInflight] = useState(0);\n const write = useCallback(\n async (fn: (gid: string) => Promise<{ count: number }>) => {\n if (!id) throw new Error(\"contentkit-ui: no group\");\n setInflight((n) => n + 1);\n try {\n return (await guarded(() => fn(id))).count;\n } finally {\n setInflight((n) => n - 1);\n }\n },\n [id, guarded],\n );\n return {\n ...list,\n saving: inflight > 0,\n add: useCallback((ms: Membership[]) => write((g) => client.entities.addMembers(g, ms)), [client, write]),\n remove: useCallback((ms: Membership[]) => write((g) => client.entities.removeMembers(g, ms)), [client, write]),\n reorder: useCallback((ms: MemberRef[]) => write((g) => client.entities.reorder(g, ms)), [client, write]),\n };\n}\n\nexport interface UseContentGroups {\n memberships: Membership[];\n /** The groups the memberships name. */\n entities: ReadonlyMap<string, GroupCard>;\n loading: boolean;\n error?: ContentKitError;\n saving: boolean;\n reload: () => void;\n /** Replaces the content's memberships, its versions' included, in these group kinds (every kind its kind joins when omitted); create links new names, creating entities of creatable kinds. */\n set: (memberships: Membership[], kinds?: string[], create?: NewEntity[]) => Promise<ContentMemberships>;\n}\n\n/** Staff: one content's memberships, its versions' included, and their replacement. */\nconst NO_MEMBERSHIPS: Membership[] = [];\n\nexport function useContentGroups(contentId: string | null | undefined, o: { language?: string; client?: ContentKitClient } = {}): UseContentGroups {\n const { client, store, scope, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const key = contentId ? keyOf(\"group-memberships\", scope, contentId, language) : null;\n const r = useResource<ContentMemberships>(store, key, { type: \"group-memberships\", id: contentId ?? undefined }, (s) => client.entities.ofContent(contentId!, language, s));\n const guarded = useGuarded();\n const [inflight, setInflight] = useState(0);\n const set = useCallback(\n async (memberships: Membership[], kinds?: string[], create?: NewEntity[]) => {\n if (!contentId) throw new Error(\"contentkit-ui: no content\");\n setInflight((n) => n + 1);\n try {\n const out = await guarded(() => client.entities.setOfContent(contentId, { kinds, memberships, ...(create?.length ? { create } : {}) }, language));\n if (key) store.set(key, out);\n return out;\n } finally {\n setInflight((n) => n - 1);\n }\n },\n [client, contentId, language, guarded, store, key],\n );\n const entities = useMemo(() => new Map((r.data?.entities ?? []).map((g) => [g.id, g])), [r.data]);\n // Stable while loading or failed: effects keyed on it must not see a new list every render.\n const memberships = useMemo(() => r.data?.memberships ?? NO_MEMBERSHIPS, [r.data]);\n return {\n memberships,\n entities,\n loading: !!key && (r.loading || !r.loaded),\n error: r.error,\n saving: inflight > 0,\n reload: r.reload,\n set,\n };\n}\n"],"mappings":"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"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ContentKitProvider, type ContentKitProviderProps } from './provider.js';
|
|
2
2
|
export { useReaderPreferences } from './reader-preferences.js';
|
|
3
|
-
export {
|
|
3
|
+
export { usePageNotices, type UsePageNotices } from './page-notices.js';
|
|
4
4
|
export { useContentKit, useContentKitClient, useContentURLs, useErrorReporter, useGuarded, GuardContext, useOptionalContentKitClient, type ContentKitContextValue, type ContentKitErrorHandler, type ContentKitErrorInfo, type ContentKitGuard, type ContentKitOperation, type Navigate, type SocialOperation, } from './context.js';
|
|
5
5
|
export { useMediaRead, type MediaReadOptions, type ReadWindow, type UseMediaRead } from './read.js';
|
|
6
6
|
export { nameIn, thumbnailOf, useMediaFolder, type FolderGroup, type MediaFolderOptions, type UseMediaFolder } from './folder.js';
|
|
@@ -14,11 +14,11 @@ export { useContentConfig, type UseContentConfig } from './config.js';
|
|
|
14
14
|
export { useFavorite, useReaction, type UseFavorite, type UseReaction } from './engagement.js';
|
|
15
15
|
export { usePoll, usePollEditor, usePolls, withVote, type PollFilter, type PollImages, type UsePoll, type UsePollEditor } from './polls.js';
|
|
16
16
|
export { useContent, useManagedContents, type ManageFilter, type UseContent } from './contents.js';
|
|
17
|
-
export { useActivity, useMyStats,
|
|
17
|
+
export { useActivity, useMyStats, type UseStats } from './stats.js';
|
|
18
18
|
export { defaultVersion, editionOf, findVersion, liveVersions, useContentDetail, type ContentDetailOptions, type UseContentDetail } from './detail.js';
|
|
19
19
|
export { useVersionParam } from './location.js';
|
|
20
|
-
export { memberId, useContentGroups, useGroup, useGroupMembers, useGroups, useKinds, useMyGroups, type GroupFilter, type GroupSort, type Member, type UseContentGroups, type UseGroup, type UseGroupMembers, type UseKinds, } from './groups.js';
|
|
21
|
-
export { beaconsFor, useBeacons, useContentFilters, useContents, useExposure, useHistory, useLockedCount, useMyFavorites, useMyReactions, useRecentSearches, useRecommendations, useReleaseDates, useDailyReleases, type UseDailyReleases, useSearch, useSimilar, useTypeahead,
|
|
20
|
+
export { memberId, useContentGroups, useGroup, useGroupMembers, useGroups, useGroupsPage, useKinds, useMyGroups, type GroupFilter, type GroupSort, type Member, type UseContentGroups, type UseGroup, type UseGroupMembers, type UseGroupsPage, type UseKinds, } from './groups.js';
|
|
21
|
+
export { beaconsFor, useBeacons, useContentFilters, useContents, useContentsPage, useExposure, useHistory, useLockedCount, useMyFavorites, useMyReactions, useRecentSearches, useRecommendations, useReleaseDates, useDailyReleases, type UseDailyReleases, useSearch, useSearchPage, useSimilar, useTypeahead, type ExposureOptions, type MyInteraction, type UseInteractions, type ReleaseDate, type UseContentFilters, type UseContentsPage, type UseExposure, type UseHistory, type UseRail, type UseRecentSearches, type UseTypeahead, } from './discovery.js';
|
|
22
22
|
export { downloadMessage, nextRelease, startDownload, useReaderPlan, useSegmentPages, useVersionDownload, type ReaderPage, type UseReaderPlan, type UseSegmentPages, type UseVersionDownload, } from './versions.js';
|
|
23
23
|
export { useContentScope, usePaged, type UseList, type UsePaged } from './use-resource.js';
|
|
24
24
|
export { ResourceStore, resourcesFor, type Page, type Resource } from './resources.js';
|
|
@@ -29,3 +29,6 @@ export { GALLERY_VIEW_KEY, PLAYER_QUALITY_KEY, useCarousel, useGalleryView, useH
|
|
|
29
29
|
export type { PlaybackProgress, ProgressReason } from './player.js';
|
|
30
30
|
export { HOVER_DELAY, InlinePreviewContext, useInlinePreview, useReducedMotion, type InlinePreviewOptions } from './inline-preview.js';
|
|
31
31
|
export { useNotifications, useNotificationUnread, type UseNotifications, type UseNotificationsOptions } from './notifications.js';
|
|
32
|
+
export { useReadingEngagement, type ReadingEngagement, type ReadingEngagementOptions } from './use-engagement.js';
|
|
33
|
+
export { usePostReading, usePostReads, type PostReadingOptions, type PostReads } from './post-reads.js';
|
|
34
|
+
export { useRememberedSort } from './remembered-sort.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ContentKitClient } from '../client/client.js';
|
|
2
|
+
import { PageNotices } from '../client/generated/wire.js';
|
|
3
|
+
export interface UsePageNotices {
|
|
4
|
+
notices: PageNotices["notices"];
|
|
5
|
+
loading: boolean;
|
|
6
|
+
reload: () => void;
|
|
7
|
+
dismiss: (notice: string) => Promise<void>;
|
|
8
|
+
restore: (notice: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/** A version's quiet notes about automatic page changes, for its editors. */
|
|
11
|
+
export declare function usePageNotices(content: string | null | undefined, version: string | null | undefined, o?: {
|
|
12
|
+
client?: ContentKitClient;
|
|
13
|
+
}): UsePageNotices;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { keyOf as e, useContentScope as t, useResource as n } from "./use-resource.js";
|
|
2
|
+
import { useCallback as r } from "react";
|
|
3
|
+
//#region src/react/page-notices.ts
|
|
4
|
+
function i(i, a, o = {}) {
|
|
5
|
+
let { client: s, store: c, scope: l } = t(o.client), u = i && a ? e("page-notices", l, i, a) : null, d = n(c, u, {
|
|
6
|
+
type: "page-notices",
|
|
7
|
+
id: a ?? void 0,
|
|
8
|
+
scope: i ?? void 0
|
|
9
|
+
}, (e) => s.versions.pageNotices(i, a, e)), f = d.data, p = r(async (e) => {
|
|
10
|
+
i && a && u && (await s.versions.dismissPageNotice(i, a, e), c.set(u, { notices: (f?.notices ?? []).filter((t) => t.id !== e) }));
|
|
11
|
+
}, [
|
|
12
|
+
s,
|
|
13
|
+
i,
|
|
14
|
+
a,
|
|
15
|
+
u,
|
|
16
|
+
c,
|
|
17
|
+
f
|
|
18
|
+
]), m = r(async (e) => {
|
|
19
|
+
i && a && u && c.set(u, await s.versions.restorePageNotice(i, a, e));
|
|
20
|
+
}, [
|
|
21
|
+
s,
|
|
22
|
+
i,
|
|
23
|
+
a,
|
|
24
|
+
u,
|
|
25
|
+
c
|
|
26
|
+
]);
|
|
27
|
+
return {
|
|
28
|
+
notices: f?.notices ?? [],
|
|
29
|
+
loading: !!u && (d.loading || !d.loaded),
|
|
30
|
+
reload: d.reload,
|
|
31
|
+
dismiss: p,
|
|
32
|
+
restore: m
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { i as usePageNotices };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=page-notices.js.map
|