feat(Icon)!: collapse duplicate share icons into one - #1191
Conversation
CUI-115. The `share` glyph was a rounded square with an arrow leaving the top-right corner, which made it visually indistinguishable from `popout` — so it read as "opens in a new tab" wherever it was used to mean "share". Vercel flagged the resulting confusion in #design-feedback. Removes that glyph and renames the survivor: `share` is now the forward arrow previously registered as `share-arrow`. `share-network` is unchanged. `share-arrow` is aliased to `share` so it keeps rendering at runtime, but it is no longer a member of the `IconName` union, so strictly-typed props fail typecheck until updated. Note the one case that cannot fail loudly: a stale `<Icon name="share" />` still compiles and silently renders the new glyph. control-plane was swept clear of `share` usages before this lands. Also fixes a latent codegen bug this surfaced: `getComponentFiles` matched every `.tsx` in the asset directories, so `Loaders.stories.tsx` was picked up as an asset and regeneration emitted a `loaders.stories` icon plus invalid TypeScript. Storybook and test files are now excluded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: eef55e9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
Storybook Preview Deployed✅ Preview URL: https://click-bbski8ujb-clickhouse.vercel.app Built from commit: |
| exported `IconName` union, so strictly-typed props (`Button.iconLeft`, | ||
| `Link.icon`, `Dropdown.Item.icon`, …) will fail typecheck until updated. | ||
|
|
||
| Also fixes a latent bug in the asset codegen: `getComponentFiles` matched every |
There was a problem hiding this comment.
internal changes usually should be omitted in changeset, it's for evident library and assets updates. Infra, meta, env, docs work is not part of it.
| 'c#': 'c-sharp', | ||
| // CUI-115: the old `share` glyph duplicated `popout` and was removed; the | ||
| // surviving share glyph moved from `share-arrow` to `share`. | ||
| 'share-arrow': 'share', |
There was a problem hiding this comment.
This line has no effect. The Icon component that consumers import never reads that map. Only an internal, unexported component does.
2 options:
- to make it work in Icon.tsx, pass name through resolveAssetName before the registry lookup, then the changeset is true (see below)
- delete this alias line and change changeset to "share-arrow is removed, rename it to share." Then the PR is purely mechanical. (easy but leaves old issue behind)
There was a problem hiding this comment.
more consistent approach - is to do the following:
- Resolve the name once in the exported Icon. src/components/Icon/Icon.tsx
+import { resolveAssetName } from '@/components/Assets/config';
-const SvgImage = ({ name, size, theme, ...props }: ImageType) => {
+const SvgImage = ({ name: rawName, size, theme, ...props }: ImageType) => {
+ const name = resolveAssetName(rawName) as ImageName;
if (Object.keys(FlagsLight).includes(name)) {
- move the alias in the config from alias to deprecated. Then on consumer side the console will output meaningful message.
Why?
We shipped two icons that nobody could tell apart.
shareandpopoutwere both a rounded square with an arrow leaving the top-right corner, soshareread as "opens in a new tab" wherever it was used to mean "share". Our friends at Vercel flagged the confusion in #design-feedback, and design agreed to collapse down to one share icon.The icon we actually want for sharing was the forward arrow, awkwardly registered as
share-arrow. So this removes the lookalike and gives the survivor the obvious name.How?
shareglyph (thepopoutduplicate).Share-Arrow.tsx→Share.tsx, soshareis now the forward-arrow glyph.share-networkis unchanged and stays in the library.types.ts/IconsLight.ts/IconsDark.tsviayarn convert:regenerate --type=icons.'share-arrow': 'share'toASSET_NAME_MAPPINGS.aliasesand repointed the legacyShareArrowdeprecated entry, so existingshare-arrowconsumers keep rendering at runtime.1.
minorvsmajor..llm/CONVENTIONS.mdsays breaking →major, and this is unambiguously breaking. But this package has never shipped amajor, and a major on0.11.0cuts 1.0.0 — that felt like not my call to make. I went withminor(→0.12.0), which is the conventional way to express a breaking change pre-1.0. Happy to switch it tomajorif you'd rather; just say so.2. I fixed a bug I didn't set out to fix.
getComponentFilesin.scripts/js/shared/svg-converter-utils.mjsmatched every.tsxin the asset directories, so the colocatedLoaders.stories.tsxwas treated as an asset. The first regenerate emitted:...and prettier then failed on the broken output. Nobody had regenerated since that stories file was added, so this was sitting there waiting for the next person. I excluded
*.stories.tsx/*.test.tsx/*.spec.tsx. It's genuinely unrelated scope — happy to split it into its own PR if you'd prefer this one stay single-purpose, though note the icon change can't be regenerated without it.Migration
sharefor a link that opens in a new tab? Switch topopout. This is the one case that will not fail loudly —Icon'snameprop resolves through aRecord<string, string>alias map, soname="share"keeps compiling and silently renders the new glyph.shareas a real "share with someone" affordance? No change needed, you get the forward arrow.share-arrow? Rename toshare. It's aliased so it still renders, but it's no longer in theIconNameunion, so strictly-typed props (Button.iconLeft,Link.icon,Dropdown.Item.icon, …) will fail typecheck until updated. That's intentional — it's how you find your call sites.Ordering⚠️ — this is why the PR is a draft
This must not merge before ClickHouse/control-plane#40485 and ClickHouse/control-plane#40490, which together sweep that repo clear of
shareusages. Because a stalename="share"can't fail loudly, merging this first would silently repaint a dozen docs links in the console with a share arrow. Undraft once both are in.I checked the other consumers I have locally (clickhouse-docs, marketing-website, demo-ui, clickpipes-platform, hyperdx-ee) and none reference
shareorshare-arrow. Residual risk is a repo I can't see.Tickets?
Contribution checklist?
buildcommand runs locallySecurity checklist?
dangerouslySetInnerHTMLPreview?
Verified locally:
yarn typecheckyarn lintyarn buildshareappears once indisttypes,share-arrowgone, onlyShare.js+Share-Network.jsremainresolveAssetName('share-arrow') === 'share',resolveAssetName('ShareArrow') === 'share'(warns as deprecated),share-arrowabsent from the registry,popoutintact, noloaders.storieskeyshareis the forward arrow, unmistakably distinct frompopoutWorth a look at the Assets/Icon → Icons Storybook gallery to confirm
shareandpopoutnow read as different icons side by side.🤖 Generated with Claude Code