diff --git a/.changeset/quiet-pans-smile.md b/.changeset/quiet-pans-smile.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/quiet-pans-smile.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/swingset/src/lib/registry.ts b/packages/swingset/src/lib/registry.ts index 8f326162f60..dd765d1559d 100644 --- a/packages/swingset/src/lib/registry.ts +++ b/packages/swingset/src/lib/registry.ts @@ -65,6 +65,7 @@ import { import { Default, Disabled as InputDisabled, + Headless as InputHeadless, Invalid, meta as inputMeta, Sizes as InputSizes, @@ -261,7 +262,14 @@ const bannerModule: StoryModule = { const buttonModule: StoryModule = { meta: buttonMeta, Primary, Sizes, Disabled }; -const inputModule: StoryModule = { meta: inputMeta, Default, Sizes: InputSizes, Disabled: InputDisabled, Invalid }; +const inputModule: StoryModule = { + meta: inputMeta, + Default, + Sizes: InputSizes, + Disabled: InputDisabled, + Invalid, + Headless: InputHeadless, +}; const popoverComponentModule: StoryModule = { meta: popoverComponentMeta, diff --git a/packages/swingset/src/stories/input.mdx b/packages/swingset/src/stories/input.mdx index 7726e8e690a..6c27ef03b7f 100644 --- a/packages/swingset/src/stories/input.mdx +++ b/packages/swingset/src/stories/input.mdx @@ -49,3 +49,12 @@ The snippet below reflects the props selected in the table above — change a pr name='Invalid' storyModule={InputStories} /> + +### Headless + +The headless variant keeps the input behavior and sizing while allowing a parent composition to provide the field chrome. + + diff --git a/packages/swingset/src/stories/input.stories.tsx b/packages/swingset/src/stories/input.stories.tsx index c5f8600ad7b..262d496dc0e 100644 --- a/packages/swingset/src/stories/input.stories.tsx +++ b/packages/swingset/src/stories/input.stories.tsx @@ -14,9 +14,11 @@ export const meta: StoryMeta = { styles: { _variants: { size: { sm: {}, md: {}, lg: {} }, + variant: { default: {}, headless: {} }, }, _defaultVariants: { size: 'md', + variant: 'default', }, }, }; @@ -75,3 +77,15 @@ export function Invalid(props: Record) { /> ); } + +export function Headless(props: Record) { + return ( +
+ +
+ ); +} diff --git a/packages/ui/src/mosaic/components/input/index.ts b/packages/ui/src/mosaic/components/input/index.ts index 188cbaa0d71..8739b78cda1 100644 --- a/packages/ui/src/mosaic/components/input/index.ts +++ b/packages/ui/src/mosaic/components/input/index.ts @@ -1,2 +1,2 @@ export { Input } from './input'; -export type { InputProps } from './input'; +export type { InputProps, InputVariant } from './input'; diff --git a/packages/ui/src/mosaic/components/input/input.styles.ts b/packages/ui/src/mosaic/components/input/input.styles.ts index 935d5003a0a..0cbdedc0aeb 100644 --- a/packages/ui/src/mosaic/components/input/input.styles.ts +++ b/packages/ui/src/mosaic/components/input/input.styles.ts @@ -23,6 +23,14 @@ export const styles = stylex.create({ color: colorVars['--cl-color-input-placeholder'], }, }, + headless: { + borderRadius: 0, + borderStyle: 'none', + borderWidth: 0, + outline: 'none', + backgroundColor: 'transparent', + boxShadow: 'none', + }, }); export const sizes = stylex.create({ diff --git a/packages/ui/src/mosaic/components/input/input.test.tsx b/packages/ui/src/mosaic/components/input/input.test.tsx index 103361daac4..31b820079cd 100644 --- a/packages/ui/src/mosaic/components/input/input.test.tsx +++ b/packages/ui/src/mosaic/components/input/input.test.tsx @@ -24,6 +24,19 @@ describe('Mosaic Input', () => { expect(screen.getByRole('textbox', { name: 'Name' })).toHaveAttribute('data-size', size); }); + it('removes field chrome with the headless variant', () => { + render( + , + ); + + const input = screen.getByRole('textbox', { name: 'Search' }); + expect(input).toHaveClass('cl-input'); + expect(input).toHaveAttribute('data-variant', 'headless'); + }); + it('reflects and forwards the disabled state', () => { render( , 'size'> { size?: 'sm' | 'md' | 'lg'; + /** Removes field chrome so a parent composition can provide it. @default 'default' */ + variant?: InputVariant; } export const Input = React.forwardRef(function MosaicInput( { size = 'md', + variant = 'default', disabled: disabledProp, required: requiredProp, render, @@ -52,8 +57,15 @@ export const Input = React.forwardRef(function Mos 'aria-labelledby': fieldProps?.['aria-labelledby'] ?? ariaLabelledBy, 'aria-describedby': fieldProps?.['aria-describedby'] ?? ariaDescribedBy, ...mergeStyleProps( - themeProps('input', { size, disabled }), - stylex.props(reset.base, inputStyles.base, styles.base, sizes[size], disabled && inputStyles.disabled), + themeProps('input', { size, variant, disabled }), + stylex.props( + reset.base, + styles.base, + sizes[size], + variant === 'default' && inputStyles.base, + variant === 'headless' && styles.headless, + variant === 'default' && disabled && inputStyles.disabled, + ), className, style, ), diff --git a/packages/ui/src/mosaic/styles/index.ts b/packages/ui/src/mosaic/styles/index.ts index bd0cfde4645..f0829c50674 100644 --- a/packages/ui/src/mosaic/styles/index.ts +++ b/packages/ui/src/mosaic/styles/index.ts @@ -49,7 +49,7 @@ export type { HeadingProps } from '../components/heading'; export { Icon, IconFrame } from '../components/icon'; export type { IconFrameProps, IconProps } from '../components/icon'; export { Input } from '../components/input'; -export type { InputProps } from '../components/input'; +export type { InputProps, InputVariant } from '../components/input'; export { Item } from '../components/item'; export type { ItemProps } from '../components/item'; export { Menu } from '../components/menu';