Skip to content

Commit f34b620

Browse files
committed
fix(ui): keep @clerk/headless out of the published mosaic export
The experimental subpath pointed at `src/mosaic/styles`, which is the StyleX build barrel: it pulls every migrated component into the graph so one stylesheet can be extracted. Publishing it made all of those components, and the headless primitive types behind them, part of the API. Give the export its own narrow entry instead. `@clerk/headless` is private, so leaving it external published a dependency that 404s on install. Bundling it broke differently: the declaration builder cannot follow the re-export chains in its emitted `dist/*.d.ts`. Correct the `tsconfig.mosaic.json` paths so it resolves to source (primitives live under `src/primitives`, so the old wildcard missed menu, popover, dialog and tabs and silently fell back to `dist`). StyleX moves to devDependencies and gets bundled: it compiles away at build time, so consumers should not inherit our version.
1 parent aee0196 commit f34b620

10 files changed

Lines changed: 48 additions & 39 deletions

File tree

packages/ui/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@
113113
"type-check": "tsc --noEmit"
114114
},
115115
"dependencies": {
116-
"@clerk/headless": "workspace:^",
117116
"@clerk/localizations": "workspace:^",
118117
"@clerk/shared": "workspace:^",
119118
"@emotion/cache": "11.11.0",
@@ -123,7 +122,6 @@
123122
"@solana/wallet-adapter-base": "catalog:module-manager",
124123
"@solana/wallet-adapter-react": "catalog:module-manager",
125124
"@solana/wallet-standard": "catalog:module-manager",
126-
"@stylexjs/stylex": "0.19.0",
127125
"@swc/helpers": "catalog:repo",
128126
"copy-to-clipboard": "3.3.3",
129127
"core-js": "catalog:repo",
@@ -133,6 +131,7 @@
133131
"qrcode.react": "4.2.0"
134132
},
135133
"devDependencies": {
134+
"@clerk/headless": "workspace:^",
136135
"@floating-ui/react-dom": "^2.1.8",
137136
"@rsdoctor/rspack-plugin": "^1.5.9",
138137
"@rspack/cli": "catalog:rspack",
@@ -141,6 +140,7 @@
141140
"@rspack/plugin-react-refresh": "catalog:rspack",
142141
"@stylexjs/eslint-plugin": "0.19.0",
143142
"@stylexjs/rollup-plugin": "0.19.0",
143+
"@stylexjs/stylex": "0.19.0",
144144
"@stylexjs/unplugin": "0.19.0",
145145
"@svgr/rollup": "^8.1.0",
146146
"@svgr/webpack": "^6.5.1",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger } from './menu';
2-
export type { MenuContentProps, MenuItemProps, MenuProps, MenuSeparatorProps, MenuTriggerProps } from './menu';
2+
export type { MenuContentProps, MenuItemProps, MenuTriggerProps } from './menu';

packages/ui/src/mosaic/components/menu/menu.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type {
22
MenuItemProps as PrimitiveMenuItemProps,
33
MenuPopupProps,
44
MenuPortalProps,
5-
MenuProps,
65
MenuSeparatorProps,
76
} from '@clerk/headless/menu';
87
import { Menu as Primitive } from '@clerk/headless/menu';
@@ -16,8 +15,6 @@ import { Icon } from '../icon';
1615
import { reset } from '../reset.styles';
1716
import { styles } from './menu.styles';
1817

19-
export type { MenuProps, MenuSeparatorProps };
20-
2118
export type MenuTriggerProps = MosaicComponentProps<'button'>;
2219

2320
/**

packages/ui/src/mosaic/components/popover/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ export type {
33
PopoverCloseProps,
44
PopoverDescriptionProps,
55
PopoverPopupProps,
6-
PopoverRootProps,
76
PopoverSize,
87
PopoverTitleProps,
98
PopoverTriggerProps,

packages/ui/src/mosaic/components/popover/popover.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { PopoverProps as HeadlessPopoverProps } from '@clerk/headless/popover';
21
import { Popover as Primitive } from '@clerk/headless/popover';
32
import * as stylex from '@stylexjs/stylex';
43
import React from 'react';
@@ -10,8 +9,6 @@ import { sizes, styles } from './popover.styles';
109

1110
export type PopoverSize = 'sm' | 'md' | 'lg';
1211

13-
export type PopoverRootProps = HeadlessPopoverProps;
14-
1512
/**
1613
* The headless parts type their props (and the `render` callback's argument) against
1714
* the raw tag props, which carry the non-standard HTML `color` attribute typed

packages/ui/src/mosaic/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Public entry for `@clerk/ui/experimental/mosaic`. The side-effect import keeps every migrated
2+
// component in the StyleX graph so the emitted `styles.css` stays complete, without making them API:
3+
// `./styles` is the build barrel, and re-exporting it would publish the headless primitive types too.
4+
import './styles';
5+
6+
export { UserButton } from './user-button/user-button';
7+
export type { UserButtonProps } from './user-button/user-button';

packages/ui/src/mosaic/styles/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@ export type { IconProps } from '../components/icon';
2424
export { Item } from '../components/item';
2525
export type { ItemProps } from '../components/item';
2626
export { Menu } from '../components/menu';
27-
export type {
28-
MenuContentProps,
29-
MenuItemProps,
30-
MenuProps,
31-
MenuSeparatorProps,
32-
MenuTriggerProps,
33-
} from '../components/menu';
27+
export type { MenuContentProps, MenuItemProps, MenuTriggerProps } from '../components/menu';
3428
export { scrollAreaRoot, scrollAreaVars, scrollAreaViewport } from '../components/scroll-area';
3529
export type { ScrollAreaGutter } from '../components/scroll-area';
3630
export { Spinner } from '../components/spinner';
@@ -43,7 +37,6 @@ export type {
4337
PopoverCloseProps,
4438
PopoverDescriptionProps,
4539
PopoverPopupProps,
46-
PopoverRootProps,
4740
PopoverSize,
4841
PopoverTitleProps,
4942
PopoverTriggerProps,

packages/ui/tsconfig.mosaic.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
// declaration bundle. Its published `dist/*.d.ts` are re-export barrels that
88
// rolldown-plugin-dts can't follow when inlining, so building types against source
99
// (the monorepo default) lets Mosaic components import headless types directly.
10+
// `utils` and `hooks` sit at the source root; every other subpath is a primitive.
1011
"@clerk/headless/utils": ["../headless/src/utils/index.ts"],
11-
"@clerk/headless/*": ["../headless/src/*"],
12+
"@clerk/headless/hooks": ["../headless/src/hooks/index.ts"],
13+
"@clerk/headless/*": ["../headless/src/primitives/*"],
1214
// Preserve the base config's test-only aliases (extends replaces `paths` wholesale).
1315
"@/core/*": ["../clerk-js/src/core/*"],
1416
"@/*": ["./src/*"],

packages/ui/tsdown.mosaic.config.mts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@ import stylexPlugin from '@stylexjs/rollup-plugin';
22
import { defineConfig } from 'tsdown';
33
import { mosaicLightningCssTargets } from './stylex-lightningcss.config.mjs';
44

5-
// Isolated Mosaic build: compiles ONLY the StyleX barrel (`src/mosaic/styles`)
6-
// with the StyleX rollup plugin, emitting transformed ESM + a single static
7-
// `styles.css` that consumers import. Kept separate from the main tsdown build so
8-
// the Emotion-based code is untouched and this entry stays Emotion-free.
5+
// Isolated Mosaic build: compiles `src/mosaic` with the StyleX rollup plugin, emitting transformed
6+
// ESM + a single static `styles.css` that consumers import. Kept separate from the main tsdown build
7+
// so the Emotion-based code is untouched and this entry stays Emotion-free.
8+
//
9+
// The entry is the narrow public surface, not the `src/mosaic/styles` barrel: the barrel exists to
10+
// pull every migrated component into the StyleX graph, and pointing the published export at it would
11+
// make all of them (and the headless primitive types behind them) API.
912
//
1013
// `useCSSLayers` wraps StyleX's atomic rules in `@layer priorityN` for correct
1114
// intra-StyleX precedence; consumers import the sheet into a layer they control
1215
// (`@import '@clerk/ui/experimental/mosaic/styles.css' layer(components)`), under which those nest
1316
// cleanly, and override from a later layer.
1417
export default defineConfig({
15-
entry: ['./src/mosaic/styles/index.ts'],
18+
entry: ['./src/mosaic/index.ts'],
1619
outDir: './dist-mosaic',
1720
format: ['esm'],
1821
dts: true,
@@ -22,10 +25,21 @@ export default defineConfig({
2225
minify: false,
2326
// Use the standard React JSX runtime, not Emotion's — the Mosaic build must be Emotion-free.
2427
tsconfig: './tsconfig.mosaic.json',
25-
// `@clerk/headless` stays external here (the main build inlines it): this entry exists to
26-
// extract `styles.css`, and only that file is exported from the package — so there is nothing
27-
// to gain from pulling the primitives and their deps into a bundle nobody imports.
28-
external: ['react', 'react-dom', '@stylexjs/stylex', /^@clerk\/headless/],
28+
// tsdown externalizes everything in `dependencies` by default, which is what we want for
29+
// `@clerk/shared`: it carries the Clerk context, so the host's copy has to be the one we read.
30+
// The two below have to override that default.
31+
//
32+
// `@clerk/headless` is a private workspace package. Left external, `@clerk/ui` publishes with a
33+
// dependency that does not exist on npm, and installing it 404s. `tsconfig.mosaic.json` already
34+
// resolves it to source, so this is the backstop: if a subpath ever escapes those `paths`, the
35+
// build fails loudly here instead of silently externalizing an unpublishable package.
36+
//
37+
// StyleX is compiled away at build time; only the tiny `props` merger survives. Bundling it keeps
38+
// it out of consumer trees entirely, so nobody inherits our StyleX version or has to have it.
39+
deps: {
40+
neverBundle: ['react', 'react-dom'],
41+
alwaysBundle: [/^@clerk\/headless/, '@stylexjs/stylex'],
42+
},
2943
// The bundle collapses every module into one, so the per-file `'use client'` directives are lost.
3044
// Everything here is interactive and hook-driven, so the entry is a client boundary in whole —
3145
// without this, importing it from a React Server Component fails.

pnpm-lock.yaml

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)