Skip to content

feat(DescriptionList): render description as link via item.to - #478

Closed
IgorShevchik wants to merge 5 commits into
mainfrom
revive/description-list-link
Closed

IgorShevchik wants to merge 5 commits into
mainfrom
revive/description-list-link

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Frozen — draft on purpose. Opened to preserve work that was stranded on an old branch, not to land it. Mark it ready when it is wanted.

Linked issue

Revives feat/description-list-linkca8b44a1 and 90457795, 2026-05-07. The original branch is untouched.

Why this exists

main was re-rooted at b55bd3e7 (2026-07-10) and now holds 173 commits. The old feature branches share no merge base with it, so a PR opened straight from feat/description-list-link reports over 1200 files changed and reads as a PR that deletes most of the repository. Both authored commits are cherry-picked onto current main instead; they applied without conflict.

Type of change

  • New feature (a non-breaking change that adds functionality)

Description

An item may render its description as a link: item.to (anything B24Link accepts) plus item.target. Without to the description renders exactly as before, so nothing existing moves — the whole change is one v-if/v-else inside the existing description slot.

to is documented as ignored when slot is set, since the consumer is rendering the description themselves.

Two things added on top of the May commits

Tests. The branch shipped none for the feature. Added two render cases and two behaviour tests — link only when to is set, href correct, plain text otherwise, and target forwarded. Mutation-checked rather than assumed: reverting DescriptionList.vue with the tests kept turns all four red, plus both new snapshots.

A prerender fix. The May example pointed at /users/owner, a route that has never existed here. Today's docs crawler follows in-example links, so docs:generate failed with [404] Page not found: /users/owner, linked from the DescriptionList page. That is not a flaw in the feature — it is an example written before the crawler behaved this way. The example now links to /docs/getting-started and https://bitrix24.com, matching what every other example with an internal to does.

Verification

Gate with CI=true: dev:prepare · lint · typecheck · test (7136 passed, 6 skipped, 310 files) · build · docs:generate (1262 routes, green after the example fix).

Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Generated by Claude Code

claude added 4 commits August 24, 2026 04:43
Add optional 'to' (and 'target') fields to DescriptionListItem so
consumers can turn a value into a B24Link without registering a custom
slot. When 'slot' is set on an item the link wrapping is skipped, so
existing custom-rendered items keep their previous behaviour.

https://claude.ai/code/session_013gYN6XWQ18LRJdDsatDpf7
Two render cases and two behaviour tests for `item.to` / `item.target`. Each
fails against the pre-feature component — verified by reverting DescriptionList.vue
with the tests kept: all four go red, plus the two render snapshots.
@IgorShevchik
IgorShevchik marked this pull request as ready for review September 14, 2026 05:58
The revived branch was recorded in August. Two things about it no longer held
against today's `main`.

Four snapshots were stale: `B24Link`'s focus-visible outline moved to
`--ui-color-design-outline-focused-stroke` and its `isaction` attribute is gone.
Regenerated, no behaviour change.

The fifth failure was real and only in the `vue` project. The fixture used
`to: '/docs'`, but the test router in `test/utils/mount.ts` registers exactly one
route, `/`. Vue Router warned, and `test/utils/console-gate.ts` turns a warning
raised during render into a failure. `Breadcrumb` and `NavigationMenu` emit the
same warning and sit in `KNOWN_NOISY_SPECS`, but that register may only shrink —
adding an entry is a decision, not a formality — so the fixture moves to `/`
instead.

Verified by mutation after the change: removing the `v-if="item.to"` branch
reddens all four cases in both projects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc

Copy link
Copy Markdown
Collaborator Author

Closing this. The implementation is fine; the case for the feature is not.

The #description slot already does this, with no library change. DescriptionListCustomSlotExample.vue shows the slot receiving item and branching per item today, so a consumer can already write:

<B24DescriptionList :items="items">
  <template #description="{ item }">
    <B24Link v-if="item.to" :to="item.to" :target="item.target">{{ item.description }}</B24Link>
    <template v-else>{{ item.description }}</template>
  </template>
</B24DescriptionList>

That is the whole diff, written by the consumer instead of shipped in the type. What the prop buys is one v-if; what it costs is two fields added permanently to the public DescriptionListItem, carried by every consumer of the component whether they link descriptions or not.

No demand. search_issues for "DescriptionList" and for a linked description returns nothing. This PR's own "Linked issue" section names no issue — it points back at the stranded May branch, and its description says outright it was opened to preserve work, not to land it.

The shape has no precedent here. Six item types put to on the item — Breadcrumb, CommandPalette, ContextMenu, DropdownMenu, FooterColumns, NavigationMenu — and in every one the whole item is the clickable link. A term/value pair where only the value half is clickable exists nowhere else, so this would start a pattern rather than follow one. If label wants a link next, there is no convention to reuse.

What the review found, recorded so a future attempt starts ahead

The JSDoc promise is false as written. DescriptionList.vue:26 and the docs say to is ignored when the item sets slot. The component enforces nothing: the <B24Link> markup sits inside the slot's fallback content, so an item with slot: 'custom' and no consumer template for that name still renders the link. Reproduced directly. And the statement misses the case that actually bites — the description slot is global, not per item, so a consumer overriding #description for unrelated reasons silently loses link rendering for every item.

One of the four tests asserts nothing. test/components/DescriptionList.spec.ts:104:

expect(plain.find('[data-slot="text"] a').exists()).toBe(false)

data-slot="text" is the top-level <p> rendered only when props.text or the text slot is present (DescriptionList.vue:150), and this mount passes neither — so the element never exists and the assertion is vacuous. The test is named "renders the description as a link only when to is set" and does not check the "when not set" half. Measured: making the link render unconditionally reddens 17 tests in the nuxt project, and this one is not among them. The selector wants to be [data-slot="description"] a, or just find('a').

Smaller things. to?: RouteLocationRaw | string — the | string is redundant, RouteLocationRaw already includes it (checked against the installed vue-router types; LinkProps.to in Link.vue:15 gets this right). DescriptionListItem's [key: string]: any means a consumer can write rel, active or download on an item with no type error and have it silently dropped, because the template binds only :to and :target. The two behaviour tests sit in a describe('accessibility') block though neither calls axe. The non-string half of the declared type — to: { name: 'x' } — is untested and throws in the vue project. to with no description renders an empty <a>.

Both playground pages still link to: '/users/owner', the dead route this PR's description says it replaced — the fix landed in the docs example only. It does not fail CI because the crawler only walks the docs site.

Not a finding, worth recording: target="_blank" is safe here. Link.vue:212-224 sets rel="noopener noreferrer" for external links and for any target other than _self, visible in the branch's own snapshot. Separately, B24Link passes a javascript: URL through to href without a scheme check — hasProtocol() treats it as external and LinkBase.vue:47-52 writes it verbatim. That is a property of B24Link shared by every component wrapping it, not something this PR introduces, and it is not fixable inside it.

A short "linking a description" note will be added to the #description slot documentation instead, so the recipe is findable without extending the API.

The branch is left as it is.


Generated by Claude Code

IgorShevchik added a commit that referenced this pull request Sep 14, 2026
#576)

#478 proposed adding `to` and `target` to `DescriptionListItem` so a description
could render as a link. It was closed: the `description` slot already receives
the item, so the same result needs no addition to the public type, and nothing
in the tracker asked for the prop.

What was missing was the recipe, not the capability. This adds a `Link in the
description` section next to the existing custom-slot section, with a runnable
example, and states the thing the closed PR's own JSDoc got wrong — the slot is
global rather than per item, so the `v-else` branch is what keeps the remaining
items rendering as plain text.

The example is a real component under `docs/app/components/content/examples/`,
so it is typechecked with the docs project rather than being prose that rots.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants