diff --git a/.changeset/8114-detail-tab-activity-timeline.md b/.changeset/8114-detail-tab-activity-timeline.md new file mode 100644 index 0000000000..7b059643bf --- /dev/null +++ b/.changeset/8114-detail-tab-activity-timeline.md @@ -0,0 +1,54 @@ +--- +'@object-ui/plugin-detail': patch +--- + +The README's Activity tab example names `record:activity`, a block this package +registers, instead of `activity-timeline`, which nothing registers +(objectui#8114). + +`README.md` ships in this package's `files`, so the example went out in every +tarball. `DetailTabs` renders a tab's `content` through +``, which makes +`content.type` an SDUI node position judged by the component registry — so a +reader copying the tab got the registry's `Unknown component type` panel +(OBJUI-001) where the timeline should be. Same shape as the `line-chart` widget +in `plugin-dashboard/README.md` (objectui#7896's census; fixed by objectui#7951) +and the fourth known instance. + +Which type replaces it was read off the registry rather than guessed, using the +repository's own derivation — `deriveRegistryKeys()` from +`scripts/check-doc-component-types.mjs`, the 649-key universe that gate judges +against: + +| key | reading | +|---|---| +| `record:activity` | REGISTERED — `packages/plugin-detail/src/index.tsx:673` | +| `activity-timeline` | absent | +| `activity` (bare) | absent — the `skipFallback: true` half | +| `related-list`, `detail-section`, `record:details` | REGISTERED (lit controls) | + +Two keys move, because naming the type alone would leave the block fed through a +key it never reads: + +- **`type: 'record:activity'`**, namespace spelled out. The registration passes + the bare name under `{ namespace: 'record', skipFallback: true }`, and + `skipFallback` is what keeps the bare name unclaimed — `record:activity` + resolves, `activity` does not. That `activity` is also the tab's own `key` is + a coincidence of spelling, and the card that filed this read the key as + evidence there was no such component type. +- **`items`, not `data`.** `RecordActivityRenderer` takes its feed from `items` + on the node, a mounted discussion context, or a self-fetch from `sys_activity` + scoped off `useRecordContext`. The last two need a record host and a bare + `` mounts neither, so the example's own intent — a caller handing + over a feed it already owns — is the first source. `data` is read on no path. + +`activityData` is retyped from `Record[]` to the exported +`FeedItem`, which puts the block under `check:doc-snippets`. No package source +and no runtime behaviour changes. + +**Still ungated, stated so this is not mistaken for coverage.** +`check:doc-types` is the gate that judges `type` literals and it deliberately +does not walk `packages/NAME/README.md` — that widening is objectui#7896's, and +objectui#7896 is blocked by this card. Measured rather than assumed: with an +unregistered type substituted back into this very block, `check:doc-snippets` +and `check:doc-types` both still exit 0. diff --git a/packages/plugin-detail/README.md b/packages/plugin-detail/README.md index 2e83f658c0..99e8728a1e 100644 --- a/packages/plugin-detail/README.md +++ b/packages/plugin-detail/README.md @@ -134,8 +134,9 @@ const accountDetail = []; +declare const activityData: FeedItem[]; declare const navigate: (url: string) => void; declare const deleteAccount: (id: string) => void; @@ -166,9 +167,11 @@ const accountDetail = ; ``` +A tab's `content` is an **SDUI node**, not a private vocabulary: `DetailTabs` +renders it with ``, +so `content.type` is resolved by the component registry and an unregistered +name paints the `Unknown component type` panel (**OBJUI-001**) instead of a +component. Author only types this repository registers. + +Two things about the Activity tab above are worth copying rather than guessing +(objectui#8114 — it previously taught `type: 'activity-timeline'`, which +nothing registers): + +- **The key is `record:activity`, with the namespace spelled out.** The + registration in `src/index.tsx` passes the bare name under + `{ namespace: 'record', skipFallback: true }`, and `skipFallback` is what + stops the bare name from also being claimed globally — so `record:activity` + resolves and `activity` resolves to nothing. `activity` is additionally a tab + **key** in the example above; the two are unrelated. +- **The feed arrives as `items`, not `data`.** `record:activity` takes its feed + from three sources, in precedence order: `items` on the node, a mounted + discussion context, or a self-fetch from `sys_activity` scoped off + `useRecordContext`. The last two need a record host; a bare `` + like the one above mounts neither, so a caller that already owns the feed + passes it in as `items` (the convention `record:history` uses for `entries`). + `data` is not a key this block reads. + +See **The `record:activity` block** in the plugin-detail guide for its declared +inputs (`types`, `limit`, `filterMode`, `showCompleted`, …). + ## Schema The DetailView component accepts a `DetailViewSchema`, declared in