// // Copyright 2023 DXOS.org // import { Primitive } from '@radix-ui/react-primitive'; import { Slot } from '@radix-ui/react-slot'; import { type Meta, type StoryObj } from '@storybook/react-vite'; import React, { PropsWithChildren } from 'react'; import { mx } from '@dxos/ui-theme'; import { withTheme } from '../testing'; import { composable, composableProps, slottable } from '../util'; import { ThemedClassName } from '../util'; /** * Radix-style composition. * All Radix primitive parts that render a DOM element accept an asChild prop. * When asChild is set to true, Radix will not render a default DOM element, * instead cloning the part's child and passing it the props and behavior required to make it functional. * https://www.radix-ui.com/primitives/docs/guides/composition */ const Outer = slottable( ({ children, asChild, priority, ...props }, forwardedRef) => { const Comp = asChild ? Slot : Primitive.div; return ( (props, { classNames: 'p-2 border border-red-500 rounded' })} ref={forwardedRef} > {children} ); }, ); const Middle = slottable(({ children, asChild, ...props }, forwardedRef) => { const Comp = asChild ? Slot : Primitive.div; return ( (props, { classNames: 'p-2 border border-red-500 rounded' })} ref={forwardedRef} > {children} ); }); const Leaf = composable(({ children, ...props }, forwardedRef) => { return ( ); }); /** This isn't a valid child for a `slottable` component. */ const Simple = ({ children, classNames }: ThemedClassName) => (
{children}
); const meta = { title: 'ui/react-ui-core/exemplars/slot', decorators: [withTheme()], parameters: { layout: 'centered', }, } satisfies Meta; export default meta; type Story = StoryObj; export const Single: Story = { render: () => ( Single asChild (non-compliant — see console) ), }; export const Nested: Story = { render: () => ( Nested asChild ), }; export const Inner: Story = { render: () => (
Leaf
), }; export const Error: Story = { render: () => ( Simple ), };