diff --git a/.changeset/mosaic-rsc-compound-components.md b/.changeset/mosaic-rsc-compound-components.md new file mode 100644 index 00000000000..662fdc65072 --- /dev/null +++ b/.changeset/mosaic-rsc-compound-components.md @@ -0,0 +1,5 @@ +--- +'@clerk/mosaic': patch +--- + +Compound components such as `Avatar`, `Banner`, `DataList`, `EmptyState`, `Entity` and `Item` can now be rendered from React Server Components, e.g. `` in a Next.js App Router page. Each compound export is now a module namespace object instead of a plain object, so `X.Part` usage is unchanged, but its parts are read-only: assigning to `X.Part` no longer replaces it. diff --git a/packages/mosaic/bundlewatch.config.json b/packages/mosaic/bundlewatch.config.json index 358d736ab82..fa538516378 100644 --- a/packages/mosaic/bundlewatch.config.json +++ b/packages/mosaic/bundlewatch.config.json @@ -1,6 +1,6 @@ { "files": [ - { "path": "./dist/index.js", "maxSize": "95KB" }, + { "path": "./dist/.bundlewatch/index.js", "maxSize": "95KB" }, { "path": "./dist/styles.css", "maxSize": "18KB" } ] } diff --git a/packages/mosaic/package.json b/packages/mosaic/package.json index cbdceb37b72..c602b73f354 100644 --- a/packages/mosaic/package.json +++ b/packages/mosaic/package.json @@ -112,6 +112,7 @@ "dist", "!dist/**/*.d.ts.map", "!dist/**/*.d.mts.map", + "!dist/.bundlewatch", "styles.css.d.ts", "CHANGELOG.md" ], @@ -119,7 +120,7 @@ "build": "pnpm build:js && pnpm build:css && pnpm check:bundle && pnpm typecheck", "build:css": "tsdown --config tsdown.css.config.mts", "build:js": "tsdown --config tsdown.config.mts", - "bundlewatch": "FORCE_COLOR=1 bundlewatch --config bundlewatch.config.json", + "bundlewatch": "node ./scripts/bundle-for-size.mjs && FORCE_COLOR=1 bundlewatch --config bundlewatch.config.json", "check:bundle": "node ./scripts/check-bundle.mjs", "clean": "rimraf ./dist ./dist-css", "dev": "tsdown --config tsdown.config.mts --watch", diff --git a/packages/mosaic/scripts/bundle-for-size.mjs b/packages/mosaic/scripts/bundle-for-size.mjs new file mode 100644 index 00000000000..953090c16b6 --- /dev/null +++ b/packages/mosaic/scripts/bundle-for-size.mjs @@ -0,0 +1,16 @@ +import { readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; + +import { build } from 'rolldown'; + +const packageDir = resolve(import.meta.dirname, '..'); +const packageJson = JSON.parse(await readFile(resolve(packageDir, 'package.json'), 'utf8')); +const externals = Object.keys({ ...packageJson.dependencies, ...packageJson.peerDependencies }); + +await build({ + input: resolve(packageDir, 'dist/index.js'), + platform: 'browser', + external: id => externals.some(name => id === name || id.startsWith(`${name}/`)), + output: { dir: resolve(packageDir, 'dist/.bundlewatch'), entryFileNames: '[name].js', format: 'esm' }, + logLevel: 'warn', +}); diff --git a/packages/mosaic/scripts/check-bundle.mjs b/packages/mosaic/scripts/check-bundle.mjs index 8d911c6048f..683787d7e28 100644 --- a/packages/mosaic/scripts/check-bundle.mjs +++ b/packages/mosaic/scripts/check-bundle.mjs @@ -1,17 +1,64 @@ import { readdir, readFile } from 'node:fs/promises'; -import { resolve } from 'node:path'; +import { dirname, relative, resolve } from 'node:path'; const distDir = resolve(import.meta.dirname, '../dist'); const jsFiles = (await readdir(distDir, { recursive: true })).filter(file => file.endsWith('.js')); const sources = await Promise.all(jsFiles.map(file => readFile(resolve(distDir, file), 'utf8'))); -const componentEntries = (await readdir(resolve(distDir, 'components'))) - .filter(file => file.endsWith('.js')) - .map(file => `components/${file}`); - -for (const entryFile of ['index.js', ...componentEntries]) { - const entry = await readFile(resolve(distDir, entryFile), 'utf8'); - if (!entry.startsWith("'use client';") && !entry.startsWith('"use client";')) { - throw new Error(`Published Mosaic JS entry ${entryFile} is missing a top-level 'use client' boundary.`); +const packageJson = JSON.parse(await readFile(resolve(import.meta.dirname, '../package.json'), 'utf8')); +const entryFiles = Object.entries(packageJson.exports) + .filter(([subpath]) => subpath === '.' || /^\.\/(components|primitives)\//.test(subpath)) + .map(([, target]) => target) + .map(target => (typeof target === 'string' ? target : target.import)) + .filter(file => file?.endsWith('.js')) + .map(file => resolve(import.meta.dirname, '..', file)); + +const isClientModule = source => source.startsWith("'use client';") || source.startsWith('"use client";'); +const importsOf = source => + [...source.matchAll(/^import\s+(?:[^'"]*?\s+from\s+)?["']([^"']+)["'];?$/gm)].map(m => m[1]); +const importsReact = source => + importsOf(source).some(specifier => specifier === 'react' || specifier.startsWith('react/')); +const code = source => + source + .replace(/\/\/.*$/gm, '') + .split('\n') + .map(line => line.trim()) + .filter(Boolean); + +const checkNamespaceEntry = async (entryFile, source) => { + const display = relative(distDir, entryFile); + const lines = code(source); + const namespaceImport = /^import \{ (\w+) \} from "(\.[^"]+)";$/; + const namespaceExport = /^export \{ (\w+ as \w+(?:, \w+ as \w+)*) \};$/; + if (!lines.every(line => namespaceImport.test(line) || namespaceExport.test(line))) { + throw new Error( + `Published Mosaic JS entry ${display} must start with 'use client' or contain only \`export * as\` namespace re-exports.`, + ); + } + for (const line of lines.filter(line => namespaceImport.test(line))) { + const [, binding, specifier] = line.match(namespaceImport); + const partsFile = resolve(dirname(entryFile), specifier); + const parts = await readFile(partsFile, 'utf8'); + if (isClientModule(parts) || !new RegExp(`^var ${binding} = /\\* @__PURE__ \\*/ __exportAll\\(`, 'm').test(parts)) { + throw new Error( + `${display} imports ${binding} from ${relative(distDir, partsFile)}, which must be a namespace object with no directive.`, + ); + } + for (const leafSpecifier of importsOf(parts).filter(specifier => specifier.startsWith('.'))) { + const leafFile = resolve(dirname(partsFile), leafSpecifier); + const leaf = await readFile(leafFile, 'utf8'); + if (importsReact(leaf) && !isClientModule(leaf)) { + throw new Error( + `${relative(distDir, leafFile)}, re-exported by the namespace ${relative(distDir, partsFile)}, imports React but is missing a top-level 'use client' boundary.`, + ); + } + } + } +}; + +for (const entryFile of entryFiles) { + const source = await readFile(entryFile, 'utf8'); + if (!isClientModule(source)) { + await checkNamespaceEntry(entryFile, source); } } diff --git a/packages/mosaic/src/components/action-bar/action-bar.parts.ts b/packages/mosaic/src/components/action-bar/action-bar.parts.ts new file mode 100644 index 00000000000..24df04f6ea6 --- /dev/null +++ b/packages/mosaic/src/components/action-bar/action-bar.parts.ts @@ -0,0 +1,7 @@ +export { + ActionBarRoot as Root, + ActionBarAction as Action, + ActionBarCount as Count, + ActionBarSeparator as Separator, + ActionBarDismiss as Dismiss, +} from './action-bar'; diff --git a/packages/mosaic/src/components/action-bar/action-bar.test.tsx b/packages/mosaic/src/components/action-bar/action-bar.test.tsx index 89c4d412103..e6941f828a5 100644 --- a/packages/mosaic/src/components/action-bar/action-bar.test.tsx +++ b/packages/mosaic/src/components/action-bar/action-bar.test.tsx @@ -7,7 +7,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { PortalProvider } from '../../primitives/portal'; import { Dialog } from '../dialog'; import { Menu } from '../menu'; -import { ActionBar } from './action-bar'; +import { ActionBar } from '.'; const testStyles = stylex.create({ positioner: { diff --git a/packages/mosaic/src/components/action-bar/action-bar.tsx b/packages/mosaic/src/components/action-bar/action-bar.tsx index 1487e528384..7e0a80c1bf3 100644 --- a/packages/mosaic/src/components/action-bar/action-bar.tsx +++ b/packages/mosaic/src/components/action-bar/action-bar.tsx @@ -1,3 +1,5 @@ +'use client'; + import { autoUpdate, FloatingFocusManager, @@ -343,4 +345,10 @@ const Dismiss = React.forwardRef(funct ); }); -export const ActionBar = { Root, Action, Count, Separator, Dismiss }; +export { + Root as ActionBarRoot, + Action as ActionBarAction, + Count as ActionBarCount, + Separator as ActionBarSeparator, + Dismiss as ActionBarDismiss, +}; diff --git a/packages/mosaic/src/components/action-bar/index.ts b/packages/mosaic/src/components/action-bar/index.ts index 4008e2405a7..5c9565a33e8 100644 --- a/packages/mosaic/src/components/action-bar/index.ts +++ b/packages/mosaic/src/components/action-bar/index.ts @@ -1,4 +1,4 @@ -export { ActionBar } from './action-bar'; +export * as ActionBar from './action-bar.parts'; export type { ActionBarActionProps, ActionBarCountProps, diff --git a/packages/mosaic/src/components/avatar/avatar.parts.ts b/packages/mosaic/src/components/avatar/avatar.parts.ts new file mode 100644 index 00000000000..457cee70d83 --- /dev/null +++ b/packages/mosaic/src/components/avatar/avatar.parts.ts @@ -0,0 +1 @@ +export { AvatarRoot as Root, AvatarImage as Image, AvatarFallback as Fallback, AvatarIcon as Icon } from './avatar'; diff --git a/packages/mosaic/src/components/avatar/avatar.test.tsx b/packages/mosaic/src/components/avatar/avatar.test.tsx index 3a7a24996d8..890a314e1c4 100644 --- a/packages/mosaic/src/components/avatar/avatar.test.tsx +++ b/packages/mosaic/src/components/avatar/avatar.test.tsx @@ -7,7 +7,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { Pen } from '../../icons/glyphs/pen'; import { Icon } from '../icon'; -import { Avatar } from './avatar'; +import { Avatar } from '.'; import { styles } from './avatar.styles'; // React reads this off the global object and ships no typing for it. diff --git a/packages/mosaic/src/components/avatar/avatar.tsx b/packages/mosaic/src/components/avatar/avatar.tsx index 5ea81429a84..13646707727 100644 --- a/packages/mosaic/src/components/avatar/avatar.tsx +++ b/packages/mosaic/src/components/avatar/avatar.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useSafeLayoutEffect } from '@clerk/shared/react'; import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -193,15 +195,4 @@ const AvatarIcon = React.forwardRef(function M ); }); -/** - * Compound avatar. `Avatar.Root` positions and sizes the box; `Avatar.Image` renders - * once its source loads; `Avatar.Fallback` holds the space until then, as a blank - * placeholder that shimmers only while an image is actually on its way; `Avatar.Icon` - * adds an optional corner affordance. - */ -export const Avatar = { - Root: AvatarRoot, - Image: AvatarImage, - Fallback: AvatarFallback, - Icon: AvatarIcon, -}; +export { AvatarRoot, AvatarImage, AvatarFallback, AvatarIcon }; diff --git a/packages/mosaic/src/components/avatar/index.ts b/packages/mosaic/src/components/avatar/index.ts index d0536b3f373..5a6816e7220 100644 --- a/packages/mosaic/src/components/avatar/index.ts +++ b/packages/mosaic/src/components/avatar/index.ts @@ -1,4 +1,8 @@ -'use client'; - -export { Avatar } from './avatar'; +/** + * Compound avatar. `Avatar.Root` positions and sizes the box; `Avatar.Image` renders + * once its source loads; `Avatar.Fallback` holds the space until then, as a blank + * placeholder that shimmers only while an image is actually on its way; `Avatar.Icon` + * adds an optional corner affordance. + */ +export * as Avatar from './avatar.parts'; export type { AvatarProps, AvatarImageProps, AvatarFallbackProps, AvatarIconProps } from './avatar'; diff --git a/packages/mosaic/src/components/banner/banner.parts.ts b/packages/mosaic/src/components/banner/banner.parts.ts new file mode 100644 index 00000000000..d8997d344b0 --- /dev/null +++ b/packages/mosaic/src/components/banner/banner.parts.ts @@ -0,0 +1 @@ +export { BannerRoot as Root, BannerLabel as Label, BannerDescription as Description } from './banner'; diff --git a/packages/mosaic/src/components/banner/banner.test.tsx b/packages/mosaic/src/components/banner/banner.test.tsx index 27b3d7233d3..4e6832a081f 100644 --- a/packages/mosaic/src/components/banner/banner.test.tsx +++ b/packages/mosaic/src/components/banner/banner.test.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { describe, expect, it } from 'vitest'; -import { Banner } from './banner'; +import { Banner } from '.'; const overrides = stylex.create({ root: { marginTop: '8px' }, diff --git a/packages/mosaic/src/components/banner/banner.tsx b/packages/mosaic/src/components/banner/banner.tsx index 2df765062fa..2a839e839df 100644 --- a/packages/mosaic/src/components/banner/banner.tsx +++ b/packages/mosaic/src/components/banner/banner.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -104,18 +106,4 @@ const Description = React.forwardRef - * Error banner - * Renew now to avoid service interruption. - * - */ -export const Banner = { Root, Label, Description }; +export { Root as BannerRoot, Label as BannerLabel, Description as BannerDescription }; diff --git a/packages/mosaic/src/components/banner/index.ts b/packages/mosaic/src/components/banner/index.ts index a82427a74ca..414f3f0cd37 100644 --- a/packages/mosaic/src/components/banner/index.ts +++ b/packages/mosaic/src/components/banner/index.ts @@ -1,4 +1,16 @@ -'use client'; - -export { Banner } from './banner'; +/** + * A tinted strip that annotates the surface it sits on with a status message. Composed through + * `Banner.Root`, `Banner.Label`, and `Banner.Description`; every part accepts the Mosaic `render` + * prop and forwards its ref. `Banner.Root` renders the icon for its `color` itself. + * + * `Banner.Root` sets no ARIA role. A banner that appears in response to something the user did + * should be given `role='status'` (or `role='alert'` for an error) so it is announced. + * + * @example + * + * Error banner + * Renew now to avoid service interruption. + * + */ +export * as Banner from './banner.parts'; export type { BannerDescriptionProps, BannerLabelProps, BannerRootProps } from './banner'; diff --git a/packages/mosaic/src/components/card/card.browser.test.tsx b/packages/mosaic/src/components/card/card.browser.test.tsx index c3a4e808cc7..e30aeb86577 100644 --- a/packages/mosaic/src/components/card/card.browser.test.tsx +++ b/packages/mosaic/src/components/card/card.browser.test.tsx @@ -4,7 +4,7 @@ import { afterEach, describe, expect, it } from 'vitest'; import { Dialog } from '../dialog'; import { Flow } from '../flow'; -import { Card } from './card'; +import { Card } from '.'; afterEach(() => cleanup()); diff --git a/packages/mosaic/src/components/card/card.parts.ts b/packages/mosaic/src/components/card/card.parts.ts new file mode 100644 index 00000000000..85633f32b99 --- /dev/null +++ b/packages/mosaic/src/components/card/card.parts.ts @@ -0,0 +1,10 @@ +export { + CardRoot as Root, + CardHeader as Header, + CardMedia as Media, + CardTitle as Title, + CardDescription as Description, + CardBanner as Banner, + CardContent as Content, + CardFooter as Footer, +} from './card'; diff --git a/packages/mosaic/src/components/card/card.test.tsx b/packages/mosaic/src/components/card/card.test.tsx index 7d9bc9953de..54fe8f94e27 100644 --- a/packages/mosaic/src/components/card/card.test.tsx +++ b/packages/mosaic/src/components/card/card.test.tsx @@ -8,7 +8,7 @@ import { Button, SubmitButton } from '../button'; import { ButtonContext } from '../button/button.context'; import { Dialog } from '../dialog'; import { Flow } from '../flow'; -import { Card } from './card'; +import { Card } from '.'; const compactCard = '@container card (max-width: 20rem)' as const; diff --git a/packages/mosaic/src/components/card/card.tsx b/packages/mosaic/src/components/card/card.tsx index 2114de982d3..e930b898cc5 100644 --- a/packages/mosaic/src/components/card/card.tsx +++ b/packages/mosaic/src/components/card/card.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -318,16 +320,13 @@ const Footer = React.forwardRef>(fun return {element}; }); -/** - * A styled surface composed through `Card.Root`, `Card.Header`, `Card.Media`, `Card.Title`, - * `Card.Description`, `Card.Banner`, `Card.Content`, and `Card.Footer`. Every part accepts the Mosaic - * `render` prop and forwards its ref. - * - * `Card.Banner` is a message slot between the header and the content. It is always rendered, and - * a `Banner` expands into it while its children hold a message, collapsing again once they are - * empty, so the slot takes `role='alert'` and stays a live region across both. - * - * Rendered as the content of a `Dialog.Popup`, the card reads that surface from `DialogContext`: - * the title and description take the popup's ARIA ids, and the header carries the dismiss button. - */ -export const Card = { Root, Header, Media, Title, Description, Banner: CardBanner, Content, Footer }; +export { + Root as CardRoot, + Header as CardHeader, + Media as CardMedia, + Title as CardTitle, + Description as CardDescription, + CardBanner, + Content as CardContent, + Footer as CardFooter, +}; diff --git a/packages/mosaic/src/components/card/index.ts b/packages/mosaic/src/components/card/index.ts index bbb91c01e4b..b78516bb3e4 100644 --- a/packages/mosaic/src/components/card/index.ts +++ b/packages/mosaic/src/components/card/index.ts @@ -1,2 +1,14 @@ -export { Card } from './card'; +/** + * A styled surface composed through `Card.Root`, `Card.Header`, `Card.Media`, `Card.Title`, + * `Card.Description`, `Card.Banner`, `Card.Content`, and `Card.Footer`. Every part accepts the Mosaic + * `render` prop and forwards its ref. + * + * `Card.Banner` is a message slot between the header and the content. It is always rendered, and + * a `Banner` expands into it while its children hold a message, collapsing again once they are + * empty, so the slot takes `role='alert'` and stays a live region across both. + * + * Rendered as the content of a `Dialog.Popup`, the card reads that surface from `DialogContext`: + * the title and description take the popup's ARIA ids, and the header carries the dismiss button. + */ +export * as Card from './card.parts'; export type { CardAlign, CardBannerProps, CardProps, CardSize } from './card'; diff --git a/packages/mosaic/src/components/combobox/combobox.parts.ts b/packages/mosaic/src/components/combobox/combobox.parts.ts new file mode 100644 index 00000000000..f41d12585ef --- /dev/null +++ b/packages/mosaic/src/components/combobox/combobox.parts.ts @@ -0,0 +1,12 @@ +export { + ComboboxRoot as Root, + ComboboxCollection as Collection, + ComboboxInput as Input, + ComboboxTrigger as Trigger, + ComboboxClear as Clear, + ComboboxPopup as Popup, + ComboboxList as List, + ComboboxOption as Option, + ComboboxOptionIndicator as OptionIndicator, + ComboboxEmpty as Empty, +} from './combobox'; diff --git a/packages/mosaic/src/components/combobox/combobox.test.tsx b/packages/mosaic/src/components/combobox/combobox.test.tsx index 1fa8bf124d5..9b3c6a7ed99 100644 --- a/packages/mosaic/src/components/combobox/combobox.test.tsx +++ b/packages/mosaic/src/components/combobox/combobox.test.tsx @@ -9,7 +9,7 @@ import { Button } from '../button'; import { Field } from '../field'; import { Icon } from '../icon'; import { InputGroup } from '../input-group'; -import { Combobox } from './combobox'; +import { Combobox } from '.'; function FloatingCombobox(props?: { onValueChange?: (value: string | null) => void; anchor?: HTMLElement }) { return ( diff --git a/packages/mosaic/src/components/combobox/combobox.tsx b/packages/mosaic/src/components/combobox/combobox.tsx index 48a510851b1..e3ac25e4206 100644 --- a/packages/mosaic/src/components/combobox/combobox.tsx +++ b/packages/mosaic/src/components/combobox/combobox.tsx @@ -248,16 +248,3 @@ export const ComboboxEmpty = React.forwardRef>(function }); }); -/** - * Mosaic `DataList` — label/value pairs for read-only detail, such as the fields describing a - * device or a payment method. Composed via dot syntax: `DataList.Root`, `DataList.Item`, - * `DataList.Label`, `DataList.Value`. Every part takes a `render` prop and forwards a ref. - * - * Semantics come free: the parts render `dl`/`dt`/`dd`, so assistive technology reads each value - * with the label it belongs to. - */ -export const DataList = { Root, Item, Label, Value }; +export { Root as DataListRoot, Item as DataListItem, Label as DataListLabel, Value as DataListValue }; diff --git a/packages/mosaic/src/components/data-list/index.ts b/packages/mosaic/src/components/data-list/index.ts index 62a63565020..6e2d88f1ff6 100644 --- a/packages/mosaic/src/components/data-list/index.ts +++ b/packages/mosaic/src/components/data-list/index.ts @@ -1,4 +1,10 @@ -'use client'; - -export { DataList } from './data-list'; +/** + * Mosaic `DataList` — label/value pairs for read-only detail, such as the fields describing a + * device or a payment method. Composed via dot syntax: `DataList.Root`, `DataList.Item`, + * `DataList.Label`, `DataList.Value`. Every part takes a `render` prop and forwards a ref. + * + * Semantics come free: the parts render `dl`/`dt`/`dd`, so assistive technology reads each value + * with the label it belongs to. + */ +export * as DataList from './data-list.parts'; export type { DataListProps } from './data-list'; diff --git a/packages/mosaic/src/components/dialog/__tests__/alert-dialog.test.tsx b/packages/mosaic/src/components/dialog/__tests__/alert-dialog.test.tsx index c424c3101da..24c2c352fff 100644 --- a/packages/mosaic/src/components/dialog/__tests__/alert-dialog.test.tsx +++ b/packages/mosaic/src/components/dialog/__tests__/alert-dialog.test.tsx @@ -4,8 +4,8 @@ import React from 'react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { Card } from '../../card'; +import { Dialog } from '..'; import type { DialogRootProps } from '../dialog'; -import { Dialog } from '../dialog'; afterEach(() => cleanup()); diff --git a/packages/mosaic/src/components/dialog/__tests__/dialog.test.tsx b/packages/mosaic/src/components/dialog/__tests__/dialog.test.tsx index af6605da7f1..f3aa49fec7e 100644 --- a/packages/mosaic/src/components/dialog/__tests__/dialog.test.tsx +++ b/packages/mosaic/src/components/dialog/__tests__/dialog.test.tsx @@ -9,8 +9,8 @@ import { colorVars, radiusVars, space } from '../../../tokens.stylex'; import { Button } from '../../button'; import { ButtonContext } from '../../button/button.context'; import { Card } from '../../card'; +import { Dialog } from '..'; import type { DialogVariant } from '../dialog'; -import { Dialog } from '../dialog'; import { styles as dialogStyles } from '../dialog.styles'; afterEach(() => cleanup()); diff --git a/packages/mosaic/src/components/dialog/__tests__/sheet-keyboard.webkit.test.tsx b/packages/mosaic/src/components/dialog/__tests__/sheet-keyboard.webkit.test.tsx index 420604a7d84..3b033a71d43 100644 --- a/packages/mosaic/src/components/dialog/__tests__/sheet-keyboard.webkit.test.tsx +++ b/packages/mosaic/src/components/dialog/__tests__/sheet-keyboard.webkit.test.tsx @@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { page } from 'vitest/browser'; import { Card } from '../../card'; -import { Dialog } from '../dialog'; +import { Dialog } from '..'; const KEYBOARD = 336; diff --git a/packages/mosaic/src/components/dialog/dialog.parts.ts b/packages/mosaic/src/components/dialog/dialog.parts.ts new file mode 100644 index 00000000000..192fb65d48c --- /dev/null +++ b/packages/mosaic/src/components/dialog/dialog.parts.ts @@ -0,0 +1,8 @@ +export { + DialogRoot as Root, + DialogTrigger as Trigger, + DialogPopup as Popup, + DialogClose as Close, + DialogCloseButton as CloseButton, + createDialogHandle as createHandle, +} from './dialog'; diff --git a/packages/mosaic/src/components/dialog/dialog.tsx b/packages/mosaic/src/components/dialog/dialog.tsx index 15d20b11af0..cb0ade6efe3 100644 --- a/packages/mosaic/src/components/dialog/dialog.tsx +++ b/packages/mosaic/src/components/dialog/dialog.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -485,44 +487,13 @@ const Popup = React.forwardRef(function Dialog ); }); -/** - * Mosaic `Dialog` — a modal surface built on the `primitives/dialog` primitive, composed - * via dot syntax: - * - * ```tsx - * - * }>Open - * - * - * - * … - * … - * - * - * - * - * ``` - * - * The dialog brings the geometry, the motion and the floating tree; the SURFACE comes from what - * is rendered inside it — a `Card` for a `card`, a `Profile` for a `profile`. Those surfaces read - * `DialogContext`, so `Card.Title` names the dialog and `Card.Header` carries its dismiss without - * either knowing it is in one. - * - * `Dialog.Popup` renders the portal, the scrim and the centering viewport itself, so those are - * not parts. `role='alertdialog'` on the root makes it an alert dialog — one that interrupts to - * ask for a decision and waits for one. In the compact band a card is a bottom sheet unless - * `compactPlacement='center'`. - * - * Each styled part spreads `themeProps` + `stylex.props` through `mergeStyleProps`, so it - * carries the public `.cl-` class and StyleX atoms while the headless part keeps its focus - * management, scroll lock, and ARIA wiring. - */ -export const Dialog = { - Root, - Trigger, - Popup, - Close, - CloseButton, - /** Creates a handle linking detached `Dialog.Trigger`s to a `Dialog.Root` anywhere in the tree. */ - createHandle: Primitive.createHandle, +/** Creates a handle linking detached `Dialog.Trigger`s to a `Dialog.Root` anywhere in the tree. */ +const createDialogHandle = Primitive.createHandle; +export { + Root as DialogRoot, + Trigger as DialogTrigger, + Popup as DialogPopup, + Close as DialogClose, + CloseButton as DialogCloseButton, + createDialogHandle, }; diff --git a/packages/mosaic/src/components/dialog/index.ts b/packages/mosaic/src/components/dialog/index.ts index e2cec98bf11..de900f06ef3 100644 --- a/packages/mosaic/src/components/dialog/index.ts +++ b/packages/mosaic/src/components/dialog/index.ts @@ -1,4 +1,37 @@ -export { Dialog, DialogContext, isInDialog } from './dialog'; +/** + * Mosaic `Dialog` — a modal surface built on the `primitives/dialog` primitive, composed + * via dot syntax: + * + * ```tsx + * + * }>Open + * + * + * + * … + * … + * + * + * + * + * ``` + * + * The dialog brings the geometry, the motion and the floating tree; the SURFACE comes from what + * is rendered inside it — a `Card` for a `card`, a `Profile` for a `profile`. Those surfaces read + * `DialogContext`, so `Card.Title` names the dialog and `Card.Header` carries its dismiss without + * either knowing it is in one. + * + * `Dialog.Popup` renders the portal, the scrim and the centering viewport itself, so those are + * not parts. `role='alertdialog'` on the root makes it an alert dialog — one that interrupts to + * ask for a decision and waits for one. In the compact band a card is a bottom sheet unless + * `compactPlacement='center'`. + * + * Each styled part spreads `themeProps` + `stylex.props` through `mergeStyleProps`, so it + * carries the public `.cl-` class and StyleX atoms while the headless part keeps its focus + * management, scroll lock, and ARIA wiring. + */ +export * as Dialog from './dialog.parts'; +export { DialogContext, isInDialog } from './dialog'; export type { DialogFocusTarget, DialogHandle, DialogOpenChangeDetails, DialogRole } from '../../primitives/dialog'; export type { DialogCloseButtonProps, diff --git a/packages/mosaic/src/components/drawer/drawer.parts.ts b/packages/mosaic/src/components/drawer/drawer.parts.ts new file mode 100644 index 00000000000..7a1c89e09a2 --- /dev/null +++ b/packages/mosaic/src/components/drawer/drawer.parts.ts @@ -0,0 +1,8 @@ +export { + DrawerRoot as Root, + DrawerPopup as Popup, + DrawerTrigger as Trigger, + DrawerTitle as Title, + DrawerDescription as Description, + DrawerClose as Close, +} from './drawer'; diff --git a/packages/mosaic/src/components/drawer/drawer.test.tsx b/packages/mosaic/src/components/drawer/drawer.test.tsx index 344a81f29b0..43360682ddc 100644 --- a/packages/mosaic/src/components/drawer/drawer.test.tsx +++ b/packages/mosaic/src/components/drawer/drawer.test.tsx @@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest'; import { MosaicProvider } from '../../mosaic-provider'; import { Dialog } from '../dialog'; -import { Drawer } from './drawer'; +import { Drawer } from '.'; function Sheet({ defaultOpen = true }: { defaultOpen?: boolean }) { return ( diff --git a/packages/mosaic/src/components/drawer/drawer.tsx b/packages/mosaic/src/components/drawer/drawer.tsx index eae62f210d3..721b995ce44 100644 --- a/packages/mosaic/src/components/drawer/drawer.tsx +++ b/packages/mosaic/src/components/drawer/drawer.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -118,17 +120,11 @@ const Description = React.forwardRef(functio }); }); -export const EmptyState = { Root, Icon: EmptyStateIcon, Label, Description, Actions }; +export { + Root as EmptyStateRoot, + EmptyStateIcon, + Label as EmptyStateLabel, + Description as EmptyStateDescription, + Actions as EmptyStateActions, +}; diff --git a/packages/mosaic/src/components/empty-state/index.ts b/packages/mosaic/src/components/empty-state/index.ts index 37ab78550f1..440e9331459 100644 --- a/packages/mosaic/src/components/empty-state/index.ts +++ b/packages/mosaic/src/components/empty-state/index.ts @@ -1,6 +1,4 @@ -'use client'; - -export { EmptyState } from './empty-state'; +export * as EmptyState from './empty-state.parts'; export type { EmptyStateActionsProps, EmptyStateDescriptionProps, diff --git a/packages/mosaic/src/components/entity/entity.browser.test.tsx b/packages/mosaic/src/components/entity/entity.browser.test.tsx index 9d6c39af54b..1dcdf1ca8c7 100644 --- a/packages/mosaic/src/components/entity/entity.browser.test.tsx +++ b/packages/mosaic/src/components/entity/entity.browser.test.tsx @@ -2,7 +2,7 @@ import { cleanup, render, screen } from '@testing-library/react'; import { afterEach, describe, expect, it } from 'vitest'; import { Badge } from '../badge'; -import { Entity } from './entity'; +import { Entity } from '.'; afterEach(() => cleanup()); diff --git a/packages/mosaic/src/components/entity/entity.parts.ts b/packages/mosaic/src/components/entity/entity.parts.ts new file mode 100644 index 00000000000..3c0790d989f --- /dev/null +++ b/packages/mosaic/src/components/entity/entity.parts.ts @@ -0,0 +1,7 @@ +export { + EntityRoot as Root, + EntityMedia as Media, + EntityContent as Content, + EntityLabel as Label, + EntityDescription as Description, +} from './entity'; diff --git a/packages/mosaic/src/components/entity/entity.test.tsx b/packages/mosaic/src/components/entity/entity.test.tsx index 00ba3e87f6f..271a66e39c7 100644 --- a/packages/mosaic/src/components/entity/entity.test.tsx +++ b/packages/mosaic/src/components/entity/entity.test.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { describe, expect, it } from 'vitest'; -import { Entity } from './entity'; +import { Entity } from '.'; const overrides = stylex.create({ root: { marginTop: '8px' }, diff --git a/packages/mosaic/src/components/entity/entity.tsx b/packages/mosaic/src/components/entity/entity.tsx index 0f3056ff5e6..eca4eccb882 100644 --- a/packages/mosaic/src/components/entity/entity.tsx +++ b/packages/mosaic/src/components/entity/entity.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -84,10 +86,10 @@ const Description = React.forwardRef }); }); -export const Entity = { - Root, - Media, - Content, - Label, - Description, +export { + Root as EntityRoot, + Media as EntityMedia, + Content as EntityContent, + Label as EntityLabel, + Description as EntityDescription, }; diff --git a/packages/mosaic/src/components/entity/index.ts b/packages/mosaic/src/components/entity/index.ts index 8740fe3de49..6b816f9d4a9 100644 --- a/packages/mosaic/src/components/entity/index.ts +++ b/packages/mosaic/src/components/entity/index.ts @@ -1,3 +1 @@ -'use client'; - -export { Entity } from './entity'; +export * as Entity from './entity.parts'; diff --git a/packages/mosaic/src/components/field/__tests__/field.ssr.test.tsx b/packages/mosaic/src/components/field/__tests__/field.ssr.test.tsx index 4709b70e55a..b2fdaf47be3 100644 --- a/packages/mosaic/src/components/field/__tests__/field.ssr.test.tsx +++ b/packages/mosaic/src/components/field/__tests__/field.ssr.test.tsx @@ -5,7 +5,7 @@ import { renderToString } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import { Input } from '../../input'; -import { Field } from '../field'; +import { Field } from '..'; describe('Mosaic Field SSR', () => { it('emits render-time relationships and defers registered relationships until hydration', () => { diff --git a/packages/mosaic/src/components/field/__tests__/field.test.tsx b/packages/mosaic/src/components/field/__tests__/field.test.tsx index 23660d012c5..2d3a05a9e7b 100644 --- a/packages/mosaic/src/components/field/__tests__/field.test.tsx +++ b/packages/mosaic/src/components/field/__tests__/field.test.tsx @@ -11,7 +11,7 @@ import { Checkbox } from '../../checkbox'; import type { FieldFeedback } from '../../form'; import { Input } from '../../input'; import { Select } from '../../select'; -import { Field } from '../field'; +import { Field } from '..'; const overrides = stylex.create({ root: { display: 'grid' }, diff --git a/packages/mosaic/src/components/field/field.parts.ts b/packages/mosaic/src/components/field/field.parts.ts new file mode 100644 index 00000000000..799a14fd0fc --- /dev/null +++ b/packages/mosaic/src/components/field/field.parts.ts @@ -0,0 +1,11 @@ +export { + FieldRoot as Root, + FieldLabel as Label, + FieldContent as Content, + FieldDescription as Description, + FieldMessage as Message, + FieldFeedback as Feedback, + FieldError as Error, + FieldSuccess as Success, + FieldHint as Hint, +} from './field'; diff --git a/packages/mosaic/src/components/field/field.tsx b/packages/mosaic/src/components/field/field.tsx index 0703224c391..6e5cb5e7f10 100644 --- a/packages/mosaic/src/components/field/field.tsx +++ b/packages/mosaic/src/components/field/field.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -323,15 +325,14 @@ const Feedback = React.forwardRef(function M ); }); -/** Styled parts for composing an automatically associated single-control field. */ -export const Field = { - Root, - Label, - Content, - Description, - Message, - Feedback, - Error: FieldError, - Success: FieldSuccess, - Hint: FieldHint, +export { + Root as FieldRoot, + Label as FieldLabel, + Content as FieldContent, + Description as FieldDescription, + Message as FieldMessage, + Feedback as FieldFeedback, + FieldError, + FieldSuccess, + FieldHint, }; diff --git a/packages/mosaic/src/components/field/index.ts b/packages/mosaic/src/components/field/index.ts index 9daf83fd93f..c707b84205c 100644 --- a/packages/mosaic/src/components/field/index.ts +++ b/packages/mosaic/src/components/field/index.ts @@ -1,4 +1,5 @@ -export { Field } from './field'; +/** Styled parts for composing an automatically associated single-control field. */ +export * as Field from './field.parts'; export type { FieldDescriptionProps, FieldErrorProps, diff --git a/packages/mosaic/src/components/flow/flow.parts.ts b/packages/mosaic/src/components/flow/flow.parts.ts new file mode 100644 index 00000000000..9908198d6d8 --- /dev/null +++ b/packages/mosaic/src/components/flow/flow.parts.ts @@ -0,0 +1 @@ +export { FlowRoot as Root, FlowStep as Step } from './flow'; diff --git a/packages/mosaic/src/components/flow/flow.test.tsx b/packages/mosaic/src/components/flow/flow.test.tsx index c198368d494..7f480d3ce2d 100644 --- a/packages/mosaic/src/components/flow/flow.test.tsx +++ b/packages/mosaic/src/components/flow/flow.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import { describe, expect, it } from 'vitest'; -import { Flow } from './flow'; +import { Flow } from '.'; describe('Mosaic Flow', () => { it('renders only the controlled step', () => { diff --git a/packages/mosaic/src/components/flow/flow.tsx b/packages/mosaic/src/components/flow/flow.tsx index d13c6ea3a5f..63defc38be1 100644 --- a/packages/mosaic/src/components/flow/flow.tsx +++ b/packages/mosaic/src/components/flow/flow.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -66,7 +68,6 @@ const Step = React.forwardRef(function FlowStep( ); }); -/** A controlled set of screens driven by opaque caller state. */ -export const Flow = { Root, Step }; +export { Root as FlowRoot, Step as FlowStep }; export type { FlowDirection }; diff --git a/packages/mosaic/src/components/flow/index.ts b/packages/mosaic/src/components/flow/index.ts index fb9a336d9c0..c0e1ec2ff4a 100644 --- a/packages/mosaic/src/components/flow/index.ts +++ b/packages/mosaic/src/components/flow/index.ts @@ -1,3 +1,4 @@ export { useFlowAutoFocus } from '../../primitives/flow'; -export { Flow } from './flow'; +/** A controlled set of screens driven by opaque caller state. */ +export * as Flow from './flow.parts'; export type { FlowDirection, FlowRootProps, FlowStepProps } from './flow'; diff --git a/packages/mosaic/src/components/input-group/index.ts b/packages/mosaic/src/components/input-group/index.ts index 1fc3f2d8f41..66fb28c3c30 100644 --- a/packages/mosaic/src/components/input-group/index.ts +++ b/packages/mosaic/src/components/input-group/index.ts @@ -1,2 +1,2 @@ -export { InputGroup } from './input-group'; +export * as InputGroup from './input-group.parts'; export type { InputGroupAddonProps, InputGroupRootProps } from './input-group'; diff --git a/packages/mosaic/src/components/input-group/input-group.parts.ts b/packages/mosaic/src/components/input-group/input-group.parts.ts new file mode 100644 index 00000000000..23cb8f0af9d --- /dev/null +++ b/packages/mosaic/src/components/input-group/input-group.parts.ts @@ -0,0 +1,6 @@ +export { + InputGroupRoot as Root, + InputGroupInput as Input, + InputGroupStart as Start, + InputGroupEnd as End, +} from './input-group'; diff --git a/packages/mosaic/src/components/input-group/input-group.test.tsx b/packages/mosaic/src/components/input-group/input-group.test.tsx index 733ff691d92..53f37ae3344 100644 --- a/packages/mosaic/src/components/input-group/input-group.test.tsx +++ b/packages/mosaic/src/components/input-group/input-group.test.tsx @@ -6,7 +6,7 @@ import { describe, expect, it, vi } from 'vitest'; import { Button } from '../button'; import { Field } from '../field'; import { Input } from '../input'; -import { InputGroup } from './input-group'; +import { InputGroup } from '.'; describe('Mosaic InputGroup', () => { it('exposes slots rather than a separate action component', () => { @@ -129,7 +129,7 @@ describe('Mosaic InputGroup', () => { }); it.each(['Start', 'End'] as const)('provides button defaults inside %s', side => { - const Slot = InputGroup[side]; + const Slot = { Start: InputGroup.Start, End: InputGroup.End }[side]; render( diff --git a/packages/mosaic/src/components/input-group/input-group.tsx b/packages/mosaic/src/components/input-group/input-group.tsx index 2399388a6e7..1c0bd59404f 100644 --- a/packages/mosaic/src/components/input-group/input-group.tsx +++ b/packages/mosaic/src/components/input-group/input-group.tsx @@ -128,4 +128,4 @@ const End = React.forwardRef(function Mos return useAddon('end', props, ref); }); -export const InputGroup = { Root, Input, Start, End }; +export { Root as InputGroupRoot, Input as InputGroupInput, Start as InputGroupStart, End as InputGroupEnd }; diff --git a/packages/mosaic/src/components/item/index.ts b/packages/mosaic/src/components/item/index.ts index a0a8cfa20eb..e4560ed0d38 100644 --- a/packages/mosaic/src/components/item/index.ts +++ b/packages/mosaic/src/components/item/index.ts @@ -1,4 +1,8 @@ -'use client'; - -export { Item } from './item'; +/** + * Mosaic `Item` — a row for lists of accounts, organizations, and settings. + * Composed via dot syntax: `Item.Root`, `Item.Media`, `Item.Content`, + * `Item.Label`, `Item.Description`, `Item.Actions`, `Item.Group`. Every part + * takes a `render` prop and forwards a ref. + */ +export * as Item from './item.parts'; export type { ItemProps } from './item'; diff --git a/packages/mosaic/src/components/item/item.parts.ts b/packages/mosaic/src/components/item/item.parts.ts new file mode 100644 index 00000000000..c35bc5885d2 --- /dev/null +++ b/packages/mosaic/src/components/item/item.parts.ts @@ -0,0 +1,9 @@ +export { + ItemRoot as Root, + ItemMedia as Media, + ItemContent as Content, + ItemLabel as Label, + ItemDescription as Description, + ItemActions as Actions, + ItemGroup as Group, +} from './item'; diff --git a/packages/mosaic/src/components/item/item.test.tsx b/packages/mosaic/src/components/item/item.test.tsx index 5dcf07fcbd1..27cf8ac815b 100644 --- a/packages/mosaic/src/components/item/item.test.tsx +++ b/packages/mosaic/src/components/item/item.test.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { describe, expect, it } from 'vitest'; -import { Item } from './item'; +import { Item } from '.'; const overrides = stylex.create({ root: { marginTop: '8px' }, diff --git a/packages/mosaic/src/components/item/item.tsx b/packages/mosaic/src/components/item/item.tsx index a694c201063..7a9ee1d3893 100644 --- a/packages/mosaic/src/components/item/item.tsx +++ b/packages/mosaic/src/components/item/item.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -166,18 +168,12 @@ const Group = React.forwardRef>(func }); }); -/** - * Mosaic `Item` — a row for lists of accounts, organizations, and settings. - * Composed via dot syntax: `Item.Root`, `Item.Media`, `Item.Content`, - * `Item.Label`, `Item.Description`, `Item.Actions`, `Item.Group`. Every part - * takes a `render` prop and forwards a ref. - */ -export const Item = { - Root, - Media, - Content, - Label, - Description, - Actions, - Group, +export { + Root as ItemRoot, + Media as ItemMedia, + Content as ItemContent, + Label as ItemLabel, + Description as ItemDescription, + Actions as ItemActions, + Group as ItemGroup, }; diff --git a/packages/mosaic/src/components/menu/index.ts b/packages/mosaic/src/components/menu/index.ts index f2855739fdd..07934197b9a 100644 --- a/packages/mosaic/src/components/menu/index.ts +++ b/packages/mosaic/src/components/menu/index.ts @@ -1,4 +1,5 @@ -export { Menu, MenuItem, MenuLabel, MenuMedia, MenuPopup, MenuSeparator, MenuTrigger } from './menu'; +export * as Menu from './menu.parts'; +export { MenuItem, MenuLabel, MenuMedia, MenuPopup, MenuSeparator, MenuTrigger } from './menu'; export type { MenuItemProps, MenuLabelProps, diff --git a/packages/mosaic/src/components/menu/menu.parts.ts b/packages/mosaic/src/components/menu/menu.parts.ts new file mode 100644 index 00000000000..01246afffbd --- /dev/null +++ b/packages/mosaic/src/components/menu/menu.parts.ts @@ -0,0 +1,10 @@ +export { + MenuRoot as Root, + MenuTrigger as Trigger, + MenuPopup as Popup, + MenuItem as Item, + MenuMedia as Media, + MenuLabel as Label, + MenuIndicator as Indicator, + MenuSeparator as Separator, +} from './menu'; diff --git a/packages/mosaic/src/components/menu/menu.test.tsx b/packages/mosaic/src/components/menu/menu.test.tsx index 7046923cea4..96417089c14 100644 --- a/packages/mosaic/src/components/menu/menu.test.tsx +++ b/packages/mosaic/src/components/menu/menu.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { describe, expect, it, vi } from 'vitest'; import { scrollAreaRoot, scrollAreaViewport } from '../scroll-area'; -import { Menu } from './menu'; +import { Menu } from '.'; const scrollClasses = stylex.props(...scrollAreaViewport()).className?.split(' ') ?? []; // The popup shares the root's atoms (both are `min-height: 0` flex columns), so only what the diff --git a/packages/mosaic/src/components/menu/menu.tsx b/packages/mosaic/src/components/menu/menu.tsx index d6d0946c9b7..1978afd0e3b 100644 --- a/packages/mosaic/src/components/menu/menu.tsx +++ b/packages/mosaic/src/components/menu/menu.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -239,15 +241,7 @@ export const MenuSeparator = React.forwardRef + * Account + * + * … + * + * + * ``` + */ +export * as Panel from './panel.parts'; +export { usePanelTitle } from './panel'; export type { PanelRootProps, PanelSectionsProps, PanelTitleProps } from './panel'; diff --git a/packages/mosaic/src/components/panel/panel.parts.ts b/packages/mosaic/src/components/panel/panel.parts.ts new file mode 100644 index 00000000000..a167c8d3a7c --- /dev/null +++ b/packages/mosaic/src/components/panel/panel.parts.ts @@ -0,0 +1 @@ +export { PanelRoot as Root, PanelTitle as Title, PanelSections as Sections } from './panel'; diff --git a/packages/mosaic/src/components/panel/panel.test.tsx b/packages/mosaic/src/components/panel/panel.test.tsx index aeb80129b88..6bced1a73ae 100644 --- a/packages/mosaic/src/components/panel/panel.test.tsx +++ b/packages/mosaic/src/components/panel/panel.test.tsx @@ -6,7 +6,7 @@ import { MosaicProvider } from '../../mosaic-provider'; import { HeadingLevelProvider } from '../heading'; import { Profile } from '../profile'; import { Section } from '../section'; -import { Panel } from './panel'; +import { Panel } from '.'; function Account() { return ( diff --git a/packages/mosaic/src/components/panel/panel.tsx b/packages/mosaic/src/components/panel/panel.tsx index 4c17fa8b7c1..ebbcb7c56ed 100644 --- a/packages/mosaic/src/components/panel/panel.tsx +++ b/packages/mosaic/src/components/panel/panel.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useMergeRefs } from '@floating-ui/react'; import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -48,7 +50,7 @@ const Title = React.forwardRef(function PanelTi return useRender({ defaultTagName: 'div', render, - ref: pageTitleRef ? null : titleRef, + ref: [ref, panelTitleRef], enabled: !inProfilePage, props: { ...mergeStyleProps(themeProps('panel-title'), stylex.props(reset.base, styles.title, xstyle), { @@ -80,16 +82,4 @@ const Sections = React.forwardRef(function P return {element}; }); -/** - * A page of content. `Panel.Sections` sit one heading level below `Panel.Title`. - * - * ```tsx - * - * Account - * - * … - * - * - * ``` - */ -export const Panel = { Root, Title, Sections }; +export { Root as PanelRoot, Title as PanelTitle, Sections as PanelSections }; diff --git a/packages/mosaic/src/components/popover/index.ts b/packages/mosaic/src/components/popover/index.ts index 8ac0cb8c76b..9f9a1f79cd6 100644 --- a/packages/mosaic/src/components/popover/index.ts +++ b/packages/mosaic/src/components/popover/index.ts @@ -1,4 +1,5 @@ -export { Popover } from './popover'; +/** A floating box anchored to a trigger. */ +export * as Popover from './popover.parts'; export type { PopoverCloseProps, PopoverDescriptionProps, diff --git a/packages/mosaic/src/components/popover/popover.parts.ts b/packages/mosaic/src/components/popover/popover.parts.ts new file mode 100644 index 00000000000..a22fb8ab6d5 --- /dev/null +++ b/packages/mosaic/src/components/popover/popover.parts.ts @@ -0,0 +1,8 @@ +export { + PopoverRoot as Root, + PopoverTrigger as Trigger, + PopoverPopup as Popup, + PopoverTitle as Title, + PopoverDescription as Description, + PopoverClose as Close, +} from './popover'; diff --git a/packages/mosaic/src/components/popover/popover.test.tsx b/packages/mosaic/src/components/popover/popover.test.tsx index 7a42e87f753..cc15f6d5f81 100644 --- a/packages/mosaic/src/components/popover/popover.test.tsx +++ b/packages/mosaic/src/components/popover/popover.test.tsx @@ -7,7 +7,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { Button } from '../button'; import { ButtonContext } from '../button/button.context'; import { Card } from '../card'; -import { Popover } from './popover'; +import { Popover } from '.'; afterEach(() => cleanup()); diff --git a/packages/mosaic/src/components/popover/popover.tsx b/packages/mosaic/src/components/popover/popover.tsx index d79f6e65a0e..3797f5116b2 100644 --- a/packages/mosaic/src/components/popover/popover.tsx +++ b/packages/mosaic/src/components/popover/popover.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -114,12 +116,12 @@ const Popup = React.forwardRef(function Popov ); }); -/** A floating box anchored to a trigger. */ -export const Popover = { - Root: Primitive.Root, - Trigger, - Popup, - Title, - Description, - Close, +const PopoverRoot = Primitive.Root; +export { + PopoverRoot, + Trigger as PopoverTrigger, + Popup as PopoverPopup, + Title as PopoverTitle, + Description as PopoverDescription, + Close as PopoverClose, }; diff --git a/packages/mosaic/src/components/profile/index.ts b/packages/mosaic/src/components/profile/index.ts index 9f9d3b6f073..3b4f29cb72d 100644 --- a/packages/mosaic/src/components/profile/index.ts +++ b/packages/mosaic/src/components/profile/index.ts @@ -1,4 +1,19 @@ -export { Profile } from './profile'; +/** + * A surface you navigate: a column of destinations beside the page each one opens. + * + * ```tsx + * + * User profile + * + * }>Account + * + * + * … + * + * + * ``` + */ +export * as Profile from './profile.parts'; export type { ProfileContentProps, ProfileElevation, diff --git a/packages/mosaic/src/components/profile/profile.parts.ts b/packages/mosaic/src/components/profile/profile.parts.ts new file mode 100644 index 00000000000..d65eaf69dcc --- /dev/null +++ b/packages/mosaic/src/components/profile/profile.parts.ts @@ -0,0 +1,9 @@ +export { + ProfileRoot as Root, + ProfileTitle as Title, + ProfileNav as Nav, + ProfileNavGroup as NavGroup, + ProfileNavItem as NavItem, + ProfileContent as Content, + ProfileContentPanel as ContentPanel, +} from './profile'; diff --git a/packages/mosaic/src/components/profile/profile.ssr.test.tsx b/packages/mosaic/src/components/profile/profile.ssr.test.tsx index 14ac0e6e101..9dd92b3073a 100644 --- a/packages/mosaic/src/components/profile/profile.ssr.test.tsx +++ b/packages/mosaic/src/components/profile/profile.ssr.test.tsx @@ -5,7 +5,7 @@ import { renderToString } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import { MosaicProvider } from '../../mosaic-provider'; -import { Profile } from './profile'; +import { Profile } from '.'; describe('Profile SSR', () => { it('names the page in the page title heading on the server', () => { diff --git a/packages/mosaic/src/components/profile/profile.test.tsx b/packages/mosaic/src/components/profile/profile.test.tsx index 0e36bedafef..dfedde448db 100644 --- a/packages/mosaic/src/components/profile/profile.test.tsx +++ b/packages/mosaic/src/components/profile/profile.test.tsx @@ -14,8 +14,8 @@ import { HeadingLevelProvider } from '../heading'; import { Icon } from '../icon'; import { Panel, usePanelTitle } from '../panel'; import { Section } from '../section'; +import { Profile } from '.'; import type { ProfileRootProps } from './profile'; -import { Profile } from './profile'; const pageTitles: Record = { account: 'Account', security: 'Security' }; @@ -369,13 +369,13 @@ describe('Profile', () => { observe = width => { Object.defineProperty(target, 'offsetWidth', { configurable: true, value: width }); Object.defineProperty(target, 'offsetHeight', { configurable: true, value: 600 }); - this.callback([], this as unknown as ResizeObserver); + this.callback([], this); }; } disconnect() {} unobserve() {} } - globalThis.ResizeObserver = FakeResizeObserver as unknown as typeof ResizeObserver; + globalThis.ResizeObserver = FakeResizeObserver; }); afterEach(() => { diff --git a/packages/mosaic/src/components/profile/profile.tsx b/packages/mosaic/src/components/profile/profile.tsx index 2e81cb034fb..3fd76968262 100644 --- a/packages/mosaic/src/components/profile/profile.tsx +++ b/packages/mosaic/src/components/profile/profile.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useSafeLayoutEffect } from '@clerk/shared/react'; import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -668,19 +670,12 @@ const ContentPanel = React.forwardRef( ); }); -/** - * A surface you navigate: a column of destinations beside the page each one opens. - * - * ```tsx - * - * User profile - * - * }>Account - * - * - * … - * - * - * ``` - */ -export const Profile = { Root, Title, Nav, NavGroup, NavItem, Content, ContentPanel }; +export { + Root as ProfileRoot, + Title as ProfileTitle, + Nav as ProfileNav, + NavGroup as ProfileNavGroup, + NavItem as ProfileNavItem, + Content as ProfileContent, + ContentPanel as ProfileContentPanel, +}; diff --git a/packages/mosaic/src/components/radio/index.ts b/packages/mosaic/src/components/radio/index.ts index 7d7a93d49cc..15d9f463e20 100644 --- a/packages/mosaic/src/components/radio/index.ts +++ b/packages/mosaic/src/components/radio/index.ts @@ -1,2 +1,2 @@ -export { Radio } from './radio'; +export * as Radio from './radio.parts'; export type { RadioCardProps, RadioGroupProps, RadioItemProps, RadioLayout, RadioSectionProps } from './radio'; diff --git a/packages/mosaic/src/components/radio/radio.parts.ts b/packages/mosaic/src/components/radio/radio.parts.ts new file mode 100644 index 00000000000..ce304a68bfb --- /dev/null +++ b/packages/mosaic/src/components/radio/radio.parts.ts @@ -0,0 +1,10 @@ +export { + RadioGroup as Group, + RadioItem as Item, + RadioSection as Section, + RadioCard as Card, + RadioMedia as Media, + RadioContent as Content, + RadioLabel as Label, + RadioDescription as Description, +} from './radio'; diff --git a/packages/mosaic/src/components/radio/radio.test-d.tsx b/packages/mosaic/src/components/radio/radio.test-d.tsx index 49e04a99021..152f1ee6a9a 100644 --- a/packages/mosaic/src/components/radio/radio.test-d.tsx +++ b/packages/mosaic/src/components/radio/radio.test-d.tsx @@ -1,6 +1,6 @@ import { describe, expectTypeOf, test } from 'vitest'; -import { Radio } from './radio'; +import { Radio } from '.'; type Access = 'all' | 'selected'; diff --git a/packages/mosaic/src/components/radio/radio.test.tsx b/packages/mosaic/src/components/radio/radio.test.tsx index 9017b7dd36b..157ed7ec4c7 100644 --- a/packages/mosaic/src/components/radio/radio.test.tsx +++ b/packages/mosaic/src/components/radio/radio.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { describe, expect, it, vi } from 'vitest'; import { Field } from '../field'; -import { Radio } from './radio'; +import { Radio } from '.'; const atoms = stylex.create({ spaced: { marginTop: '8px' }, diff --git a/packages/mosaic/src/components/radio/radio.tsx b/packages/mosaic/src/components/radio/radio.tsx index 1c30af39a46..d67e50e9439 100644 --- a/packages/mosaic/src/components/radio/radio.tsx +++ b/packages/mosaic/src/components/radio/radio.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -262,13 +264,8 @@ const RadioCard = React.forwardRef(function Mo ); }); -export const Radio = { - Group: RadioGroup, - Item: RadioItem, - Section: RadioSection, - Card: RadioCard, - Media: Item.Media, - Content: Item.Content, - Label: Item.Label, - Description: Item.Description, -}; +const RadioMedia = Item.Media; +const RadioContent = Item.Content; +const RadioLabel = Item.Label; +const RadioDescription = Item.Description; +export { RadioGroup, RadioItem, RadioSection, RadioCard, RadioMedia, RadioContent, RadioLabel, RadioDescription }; diff --git a/packages/mosaic/src/components/section/index.ts b/packages/mosaic/src/components/section/index.ts index 540434b0ca1..6289fa8ec37 100644 --- a/packages/mosaic/src/components/section/index.ts +++ b/packages/mosaic/src/components/section/index.ts @@ -1,4 +1,9 @@ -export { Section } from './section'; +/** + * A compound component for a topic of settings. `Section.Root` stacks groups; each `Section.Group` + * is named by the `Section.Title` in its `Section.Header`, above a `Section.Body` card holding + * either `Section.Row`s (one setting each) or a `Section.Items` list of values. + */ +export * as Section from './section.parts'; export { sectionCompactStyles } from './section.styles'; export type { SectionActionsProps, diff --git a/packages/mosaic/src/components/section/section.parts.ts b/packages/mosaic/src/components/section/section.parts.ts new file mode 100644 index 00000000000..3350feb29ff --- /dev/null +++ b/packages/mosaic/src/components/section/section.parts.ts @@ -0,0 +1,17 @@ +export { + SectionRoot as Root, + SectionGroup as Group, + SectionHeader as Header, + SectionTitle as Title, + SectionBody as Body, + SectionRow as Row, + SectionItems as Items, + SectionItem as Item, + SectionMedia as Media, + SectionContent as Content, + SectionLabel as Label, + SectionDescription as Description, + SectionActions as Actions, + SectionNote as Note, + SectionError as Error, +} from './section'; diff --git a/packages/mosaic/src/components/section/section.test.tsx b/packages/mosaic/src/components/section/section.test.tsx index b862b4a3271..29f56d4ebc4 100644 --- a/packages/mosaic/src/components/section/section.test.tsx +++ b/packages/mosaic/src/components/section/section.test.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { describe, expect, it } from 'vitest'; import { HeadingLevelProvider } from '../heading'; -import { Section } from './section'; +import { Section } from '.'; const overrides = stylex.create({ root: { containerType: 'inline-size' }, diff --git a/packages/mosaic/src/components/section/section.tsx b/packages/mosaic/src/components/section/section.tsx index e3435143c62..d0e7d3768c4 100644 --- a/packages/mosaic/src/components/section/section.tsx +++ b/packages/mosaic/src/components/section/section.tsx @@ -1,3 +1,5 @@ +'use client'; + import { useSafeLayoutEffect } from '@clerk/shared/react'; import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -347,25 +349,20 @@ const SectionError = React.forwardRef(f }); }); -/** - * A compound component for a topic of settings. `Section.Root` stacks groups; each `Section.Group` - * is named by the `Section.Title` in its `Section.Header`, above a `Section.Body` card holding - * either `Section.Row`s (one setting each) or a `Section.Items` list of values. - */ -export const Section = { - Root, - Group, - Header, - Title, - Body, - Row, - Items, - Item, - Media, - Content, - Label, - Description, - Actions, - Note, - Error: SectionError, +export { + Root as SectionRoot, + Group as SectionGroup, + Header as SectionHeader, + Title as SectionTitle, + Body as SectionBody, + Row as SectionRow, + Items as SectionItems, + Item as SectionItem, + Media as SectionMedia, + Content as SectionContent, + Label as SectionLabel, + Description as SectionDescription, + Actions as SectionActions, + Note as SectionNote, + SectionError, }; diff --git a/packages/mosaic/src/components/segmented-control/index.ts b/packages/mosaic/src/components/segmented-control/index.ts index 19245cca3e7..3664427d9d5 100644 --- a/packages/mosaic/src/components/segmented-control/index.ts +++ b/packages/mosaic/src/components/segmented-control/index.ts @@ -1,2 +1,2 @@ -export { SegmentedControl } from './segmented-control'; +export * as SegmentedControl from './segmented-control.parts'; export type { SegmentedControlItemProps, SegmentedControlRootProps } from './segmented-control'; diff --git a/packages/mosaic/src/components/segmented-control/segmented-control.parts.ts b/packages/mosaic/src/components/segmented-control/segmented-control.parts.ts new file mode 100644 index 00000000000..3a1388e1b5c --- /dev/null +++ b/packages/mosaic/src/components/segmented-control/segmented-control.parts.ts @@ -0,0 +1 @@ +export { SegmentedControlRoot as Root, SegmentedControlItem as Item } from './segmented-control'; diff --git a/packages/mosaic/src/components/segmented-control/segmented-control.test-d.tsx b/packages/mosaic/src/components/segmented-control/segmented-control.test-d.tsx index a06c6d33696..1b8f510ae09 100644 --- a/packages/mosaic/src/components/segmented-control/segmented-control.test-d.tsx +++ b/packages/mosaic/src/components/segmented-control/segmented-control.test-d.tsx @@ -1,6 +1,6 @@ import { describe, expectTypeOf, test } from 'vitest'; -import { SegmentedControl } from './segmented-control'; +import { SegmentedControl } from '.'; type Access = 'all' | 'selected'; diff --git a/packages/mosaic/src/components/segmented-control/segmented-control.test.tsx b/packages/mosaic/src/components/segmented-control/segmented-control.test.tsx index b16df7a9750..366aafa5258 100644 --- a/packages/mosaic/src/components/segmented-control/segmented-control.test.tsx +++ b/packages/mosaic/src/components/segmented-control/segmented-control.test.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { describe, expect, it, vi } from 'vitest'; import { DirectionProvider } from '../../primitives/direction-provider'; -import { SegmentedControl } from './segmented-control'; +import { SegmentedControl } from '.'; function BillingPeriod(props: Partial>) { return ( diff --git a/packages/mosaic/src/components/segmented-control/segmented-control.tsx b/packages/mosaic/src/components/segmented-control/segmented-control.tsx index 5e0db2801c7..7017435922a 100644 --- a/packages/mosaic/src/components/segmented-control/segmented-control.tsx +++ b/packages/mosaic/src/components/segmented-control/segmented-control.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -61,7 +63,4 @@ const Item = React.forwardRef(func ); }); -export const SegmentedControl = { - Root, - Item, -}; +export { Root as SegmentedControlRoot, Item as SegmentedControlItem }; diff --git a/packages/mosaic/src/components/select/index.ts b/packages/mosaic/src/components/select/index.ts index 3994f585f06..1b38ac74676 100644 --- a/packages/mosaic/src/components/select/index.ts +++ b/packages/mosaic/src/components/select/index.ts @@ -1,5 +1,5 @@ +export * as Select from './select.parts'; export { - Select, SelectContent, SelectDescription, SelectLabel, diff --git a/packages/mosaic/src/components/select/select.parts.ts b/packages/mosaic/src/components/select/select.parts.ts new file mode 100644 index 00000000000..acc1d4143c8 --- /dev/null +++ b/packages/mosaic/src/components/select/select.parts.ts @@ -0,0 +1,10 @@ +export { + SelectRoot as Root, + SelectTrigger as Trigger, + SelectPopup as Popup, + SelectOption as Option, + SelectMedia as Media, + SelectContent as Content, + SelectLabel as Label, + SelectDescription as Description, +} from './select'; diff --git a/packages/mosaic/src/components/select/select.test-d.tsx b/packages/mosaic/src/components/select/select.test-d.tsx index 2d45ce0b30c..d921d4d3472 100644 --- a/packages/mosaic/src/components/select/select.test-d.tsx +++ b/packages/mosaic/src/components/select/select.test-d.tsx @@ -1,6 +1,6 @@ import { describe, expectTypeOf, test } from 'vitest'; -import { Select } from './select'; +import { Select } from '.'; type Expiration = '1d' | '7d'; diff --git a/packages/mosaic/src/components/select/select.test.tsx b/packages/mosaic/src/components/select/select.test.tsx index 5e52777d0dd..e4af1a22786 100644 --- a/packages/mosaic/src/components/select/select.test.tsx +++ b/packages/mosaic/src/components/select/select.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { describe, expect, it, vi } from 'vitest'; import { Field } from '../field'; -import { Select } from './select'; +import { Select } from '.'; const roles = [ { value: 'all', label: 'All roles' }, diff --git a/packages/mosaic/src/components/select/select.tsx b/packages/mosaic/src/components/select/select.tsx index a302c047eac..f432f6acf7f 100644 --- a/packages/mosaic/src/components/select/select.tsx +++ b/packages/mosaic/src/components/select/select.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -381,14 +383,3 @@ export const SelectDescription = React.forwardRef ); }); -export const Table = { - Root, - Toolbar, - Search, - Header, - Column, - Body, - Row, - Cell, - SelectionColumn, - SelectionCell, - ExpandButton, +export { + Root as TableRoot, + Toolbar as TableToolbar, + Search as TableSearch, + Header as TableHeader, + Column as TableColumn, + Body as TableBody, + Row as TableRow, + Cell as TableCell, + SelectionColumn as TableSelectionColumn, + SelectionCell as TableSelectionCell, + ExpandButton as TableExpandButton, }; diff --git a/packages/mosaic/src/components/tabs/index.ts b/packages/mosaic/src/components/tabs/index.ts index 9cf08932446..86941410a2c 100644 --- a/packages/mosaic/src/components/tabs/index.ts +++ b/packages/mosaic/src/components/tabs/index.ts @@ -1,4 +1,4 @@ -export { Tabs } from './tabs'; +export * as Tabs from './tabs.parts'; export type { TabsListProps, TabsPanelProps, diff --git a/packages/mosaic/src/components/tabs/tabs.parts.ts b/packages/mosaic/src/components/tabs/tabs.parts.ts new file mode 100644 index 00000000000..0955d6e4d7b --- /dev/null +++ b/packages/mosaic/src/components/tabs/tabs.parts.ts @@ -0,0 +1,8 @@ +export { + TabsRoot as Root, + TabsList as List, + TabsTab as Tab, + TabsTrigger as Trigger, + TabsPanels as Panels, + TabsPanel as Panel, +} from './tabs'; diff --git a/packages/mosaic/src/components/tabs/tabs.test.tsx b/packages/mosaic/src/components/tabs/tabs.test.tsx index 8d00af583a6..cc4090462ca 100644 --- a/packages/mosaic/src/components/tabs/tabs.test.tsx +++ b/packages/mosaic/src/components/tabs/tabs.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { describe, expect, it } from 'vitest'; -import { Tabs } from './tabs'; +import { Tabs } from '.'; import { styles } from './tabs.styles'; const atoms = stylex.create({ diff --git a/packages/mosaic/src/components/tabs/tabs.tsx b/packages/mosaic/src/components/tabs/tabs.tsx index c1380c2671f..2a5e0f20585 100644 --- a/packages/mosaic/src/components/tabs/tabs.tsx +++ b/packages/mosaic/src/components/tabs/tabs.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -112,11 +114,11 @@ const Panels = React.forwardRef(function Mosaic }); }); -export const Tabs = { - Root, - List, - Tab, - Trigger, - Panels, - Panel, +export { + Root as TabsRoot, + List as TabsList, + Tab as TabsTab, + Trigger as TabsTrigger, + Panels as TabsPanels, + Panel as TabsPanel, }; diff --git a/packages/mosaic/src/components/tooltip/index.ts b/packages/mosaic/src/components/tooltip/index.ts index bea23eca103..a56818220ce 100644 --- a/packages/mosaic/src/components/tooltip/index.ts +++ b/packages/mosaic/src/components/tooltip/index.ts @@ -1,2 +1,2 @@ -export { Tooltip } from './tooltip'; +export * as Tooltip from './tooltip.parts'; export type { TooltipPopupProps, TooltipRootProps, TooltipTriggerProps } from './tooltip'; diff --git a/packages/mosaic/src/components/tooltip/tooltip.parts.ts b/packages/mosaic/src/components/tooltip/tooltip.parts.ts new file mode 100644 index 00000000000..5a09be7d3f4 --- /dev/null +++ b/packages/mosaic/src/components/tooltip/tooltip.parts.ts @@ -0,0 +1,6 @@ +export { + TooltipRoot as Root, + TooltipGroup as Group, + TooltipTrigger as Trigger, + TooltipPopup as Popup, +} from './tooltip'; diff --git a/packages/mosaic/src/components/tooltip/tooltip.test.tsx b/packages/mosaic/src/components/tooltip/tooltip.test.tsx index 88d588d0bbf..239ae3f4699 100644 --- a/packages/mosaic/src/components/tooltip/tooltip.test.tsx +++ b/packages/mosaic/src/components/tooltip/tooltip.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { afterEach, describe, expect, it } from 'vitest'; -import { Tooltip } from './tooltip'; +import { Tooltip } from '.'; afterEach(() => cleanup()); diff --git a/packages/mosaic/src/components/tooltip/tooltip.tsx b/packages/mosaic/src/components/tooltip/tooltip.tsx index cdc41232a48..dffffb41e3e 100644 --- a/packages/mosaic/src/components/tooltip/tooltip.tsx +++ b/packages/mosaic/src/components/tooltip/tooltip.tsx @@ -1,3 +1,5 @@ +'use client'; + import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -42,9 +44,6 @@ const Popup = React.forwardRef(function Toolt ); }); -export const Tooltip = { - Root: Primitive.Root, - Group: Primitive.Group, - Trigger, - Popup, -}; +const TooltipRoot = Primitive.Root; +const TooltipGroup = Primitive.Group; +export { TooltipRoot, TooltipGroup, Trigger as TooltipTrigger, Popup as TooltipPopup }; diff --git a/packages/mosaic/tsdown.config.mts b/packages/mosaic/tsdown.config.mts index c913e5a9b48..504fdb98b8e 100644 --- a/packages/mosaic/tsdown.config.mts +++ b/packages/mosaic/tsdown.config.mts @@ -37,6 +37,7 @@ export default defineConfig({ tsgo: { path: getTypeScriptExecutablePath() }, }, clean: true, + unbundle: true, target: 'es2022', platform: 'browser', minify: false,