Skip to content

fix(react): pin and upgrade @telegraph/combobox to 0.6.0 - #1068

Merged
kylemcd merged 9 commits into
mainfrom
kyle-kno-15137-js-sdk-pin-and-upgrade-telegraphcombobox-to-060
Sep 10, 2026
Merged

fix(react): pin and upgrade @telegraph/combobox to 0.6.0#1068
kylemcd merged 9 commits into
mainfrom
kyle-kno-15137-js-sdk-pin-and-upgrade-telegraphcombobox-to-060

Conversation

@kylemcd

@kylemcd kylemcd commented Sep 4, 2026

Copy link
Copy Markdown
Member

Description

@knocklabs/react declared ">=0.5.0" for @telegraph/combobox, so every install already resolved to 0.6.0. that release is a Base UI rewrite, and our code was only ever tested on 0.5.0. this pins the range to ^0.6.0 and takes the upgrade deliberately.

  • screen readers announce Slack channel names, not raw ids like C0123ABC
  • an option's name comes from its children, and ours are an icon beside the name, so 0.6.0 falls back to the id
  • the trigger takes its aria-label from us instead, which leaves the icon and the layout untouched
  • both multi-select call sites narrow value, which 0.6.0 rejects as (string | undefined)[]
  • sortByDisplayName copies before sorting, so it stops reordering SWR's cached channels
  • every other @telegraph/* range is pinned too, and select@0.2.0 drops the duplicate combobox 0.5.0
  • 12 new tests cover the trigger names, the option icon, and the sort, where there was no coverage
  • plus the lockfile bump, the example-app ranges that manypkg keeps in step, and jsdom polyfills for Base UI

nothing renders differently: the diff against main changes no markup in any of the three comboboxes.

@knocklabs/react declared "@telegraph/combobox": ">=0.5.0", so every
consumer resolved to whatever was latest on npm — including 0.6.0, the
Base UI rewrite, against code only ever tested on 0.5.0. Pin the range to
^0.6.0 across the workspace, bump the lockfile, and take the upgrade
deliberately.

Two things the upgrade needed:

- SlackChannelCombobox renders an icon beside each channel name, so its
  options have element children. 0.6.0 resolves an option's label as
  `label || children || value` and falls back to `value` whenever the
  label is not a string, so the trigger announced the raw Slack channel
  id. Each option now passes an explicit `label`.
- 0.6.0 tightened Combobox.Root's `value` type, which no longer accepts
  `(string | undefined)[]`. Both multi-select call sites now narrow.

Add coverage for all three comboboxes, which had none, and polyfill
ResizeObserver and scrollIntoView so Base UI can mount under jsdom.
@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown

KNO-15137

@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
javascript-ms-teams-connect-example Ready Ready Preview Sep 8, 2026 10:03pm UTC
javascript-nextjs-example Ready Ready Preview Sep 8, 2026 10:03pm UTC
javascript-slack-connect-example Ready Ready Preview Sep 8, 2026 10:03pm UTC
javascript-slack-kit-example Ready Ready Preview Sep 8, 2026 10:03pm UTC

Request Review

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 668e839

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@knocklabs/react Patch
ms-teams-connect-example Patch
nextjs-app-dir-example Patch
slack-connect-example Patch
slack-kit-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 1.73kB (0.29%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
@knocklabs/react-react-esm 154.73kB 869 bytes (0.56%) ⬆️
@knocklabs/react-react-cjs 132.01kB 862 bytes (0.66%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: @knocklabs/react-react-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
modules/guide/components/Toolbar/styles.inline.mjs 769 bytes 26.25kB 3.02%
modules/ms-*.mjs 5 bytes 233 bytes 2.19%
modules/ms-*.mjs -38 bytes 2.22kB -1.68%
modules/slack/components/SlackChannelCombobox/SlackChannelCombobox.mjs 133 bytes 3.84kB 3.59%

Files in modules/ms-*.mjs:

  • ./src/modules/ms-teams/utils.ts → Total Size: 187 bytes

Files in modules/ms-*.mjs:

  • ./src/modules/ms-teams/components/MsTeamsChannelCombobox/MsTeamsChannelInTeamCombobox.tsx → Total Size: 2.75kB

Files in modules/slack/components/SlackChannelCombobox/SlackChannelCombobox.mjs:

  • ./src/modules/slack/components/SlackChannelCombobox/SlackChannelCombobox.tsx → Total Size: 4.89kB
view changes for bundle: @knocklabs/react-react-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
modules/guide/components/Toolbar/styles.inline.js 769 bytes 26.16kB 3.03%
modules/ms-*.js 5 bytes 175 bytes 2.94%
modules/ms-*.js -38 bytes 1.72kB -2.16%
modules/slack/components/SlackChannelCombobox/SlackChannelCombobox.js 126 bytes 3.0kB 4.38%

Files in modules/ms-*.js:

  • ./src/modules/ms-teams/utils.ts → Total Size: 187 bytes

Files in modules/ms-*.js:

  • ./src/modules/ms-teams/components/MsTeamsChannelCombobox/MsTeamsChannelInTeamCombobox.tsx → Total Size: 3.32kB

Files in modules/slack/components/SlackChannelCombobox/SlackChannelCombobox.js:

  • ./src/modules/slack/components/SlackChannelCombobox/SlackChannelCombobox.tsx → Total Size: 5.71kB

useMsTeamsChannels returns a reference straight into SWR's cache, so
sorting in place reordered the cached array for every other reader of
that key — including apps that call the hook themselves, since both MS
Teams hooks are public exports. Copy first, matching the Slack helper,
and take a readonly parameter so a bare .sort() no longer compiles.
Combobox.Option renders `label || children || value`, so the string label
added for the accessible name stopped the option's children rendering.
That silently dropped the hash/lock icon from both the dropdown row and
the selected tags, and it is the only place a channel's private/public
state is shown.

Move the icon into the option's trailing icon slot. The leading slot is
not available: OptionItemLeading returns the selection check early for
any selectable combobox, so `leadingIcon` and `leadingComponent` are both
ignored there.

The icon now sits at the right edge of the row rather than beside the
name, and the trigger's tags still show the name alone, because
TriggerTagText renders `label || value` and never sees the icon.
Every other @telegraph/* dependency was still an open >= range, so an
install resolved to whatever npm had newest rather than something this
package was built against — the same problem the combobox pin fixed.

The one with a real consequence was @telegraph/select, stuck on 0.1.0,
which hard-pins @telegraph/combobox at 0.5.0. Consumers were getting two
copies of the combobox. 0.2.0 depends on 0.6.0, so the lockfile now
carries a single entry.
Earlier commits fixed the trigger's accessible name by giving each option
a string `label`. An option renders `label || children || value`, so that
also stopped the children rendering and cost the hash/lock icon; routing
it through `trailingIcon` got it back but moved it to the right edge, and
the trigger's tags lost it entirely.

Combobox.Trigger spreads consumer props over its own `aria-label`, so the
name can be set directly and the markup left alone. The options go back
to exactly what main renders, and the icon returns to its old position in
both the dropdown and the tags.

The option's own name in the listbox needs nothing: its icon is
aria-hidden, so the name already resolves from its text.
currentConnectedChannels and triggerLabel each built their own Map over
slackChannels, so every render paid for two passes over a list that can
hold a thousand channels. Lift one memoized map and read both from it.
The combobox entry described the accessible-name bug but, once the fix
moved to an aria-label on the trigger, no longer described the fix — and
its other half repeated the dependency pin that the telegraph entry
already covers. Consumers would have read both twice, one of them as an
unresolved defect.
Both "ignores connections that are no longer available / belong to
another team" cases asserted only on the trigger's accessible name. A
selected id with no matching option resolves to undefined and is filtered
out of that name, so removing the guard each test exists to cover left
the name unchanged and both passed regardless.

The stray id does render a tag, since the trigger falls back to the raw
value when no option matches, so assert the tag is absent instead.
Three branches added by this PR had no test behind them: connected
channels arriving undefined before the first load, a connection with no
channel id at all, and the trigger label falling through to "" when
nothing is connected and the error state carries no label to show.

That last one is the reason the label is built as a string rather than
left undefined, so it is worth pinning down.
@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.38%. Comparing base (f45490b) to head (668e839).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1068      +/-   ##
==========================================
+ Coverage   73.13%   75.38%   +2.24%     
==========================================
  Files         139      139              
  Lines        4366     4371       +5     
  Branches     1283     1283              
==========================================
+ Hits         3193     3295     +102     
+ Misses       1056      976      -80     
+ Partials      117      100      -17     
Files with missing lines Coverage Δ
...msChannelCombobox/MsTeamsChannelInTeamCombobox.tsx 74.28% <100.00%> (+71.50%) ⬆️
packages/react/src/modules/ms-teams/utils.ts 100.00% <100.00%> (ø)
...ents/SlackChannelCombobox/SlackChannelCombobox.tsx 88.70% <100.00%> (+85.13%) ⬆️

... and 3 files with indirect coverage changes

@kylemcd
kylemcd merged commit 62205a1 into main Sep 10, 2026
12 checks passed
@kylemcd
kylemcd deleted the kyle-kno-15137-js-sdk-pin-and-upgrade-telegraphcombobox-to-060 branch September 10, 2026 19:20
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