Skip to content

Commit

Permalink
fix: migrate the rest of the components to polymorphic
Browse files Browse the repository at this point in the history
  • Loading branch information
LexSwed committed Dec 29, 2022
1 parent 1dfca93 commit 7f313f9
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 120 deletions.
2 changes: 1 addition & 1 deletion src/lib/chip/chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const Chip = forwardRef(function Chip<T>(
const selectable = typeof props['aria-selected'] !== 'undefined';
return (
<Flex
{...props}
{...(props as any)}
main={main}
cross={cross}
gap={gap}
Expand Down
11 changes: 0 additions & 11 deletions src/lib/form-field/form-field.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@
padding-inline-start: theme('spacing.3');
}
}
&:has(.size--xl) {
& :where(.label, .hint) {
padding-inline-start: theme('spacing.3');
}
}
}
.label {
text-overflow: ellipsis;
Expand Down Expand Up @@ -130,12 +125,6 @@
line-height: theme('spacing.12');
@apply text-lg;
}
.size--xl {
padding-block: theme('spacing.1');
padding-inline: theme('spacing.3');
font-weight: 800;
@apply text-2xl;
}

/* Validity */
.validity--valid {
Expand Down
1 change: 0 additions & 1 deletion src/lib/form-field/form-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ export const fieldBoxCss = css(styles.field, {
sm: styles['size--sm'],
md: styles['size--md'],
lg: styles['size--lg'],
xl: styles['size--xl'],
},
validity: {
valid: styles['validity--valid'],
Expand Down
19 changes: 8 additions & 11 deletions src/lib/heading/heading.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import { ElementType, forwardRef } from 'react';
import { forwardRef } from 'react';
import { classed as css, VariantProps } from '@tw-classed/core';
import { clsx } from 'clsx';

import type { PolyProps, PolyRef } from '../utils/polymorphic';
import type { ForwardRefComponent } from '../utils/polymorphic';

import styles from './heading.module.css';

type HeadingProps<C extends ElementType = 'h1'> = PolyProps<C, HeadingVariants & { disabled?: boolean }>;
type HeadingComponent = <C extends ElementType = 'h1'>(props: HeadingProps<C>) => React.ReactElement | null;
interface HeadingProps extends HeadingVariants {
disabled?: boolean;
}

export const Heading: HeadingComponent = forwardRef(
<C extends ElementType = 'h1'>(
{ as, variant = 'default', level = '1', dense = true, className, ...props }: HeadingProps<C>,
ref: PolyRef<C>
) => {
const Component = as || 'h1';
export const Heading = forwardRef(
({ as: Component = 'h1', variant = 'default', level = '1', dense = true, className, ...props }, ref) => {
return <Component className={clsx(headingCss({ variant, level, dense }), className)} {...props} ref={ref} />;
}
);
) as ForwardRefComponent<'h1', HeadingProps>;

type HeadingVariants = VariantProps<typeof headingCss>;
const headingCss = css(styles.heading, {
Expand Down
63 changes: 28 additions & 35 deletions src/lib/menu-list/menu-list.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as RovingFocusGroup from '@radix-ui/react-roving-focus';

import { clsx } from 'clsx';
import { ComponentProps, ElementType, forwardRef, ReactElement } from 'react';
import { ComponentProps, forwardRef } from 'react';

import { Flex } from '../flex';
import { useAllHandlers, useKeyboardHandles } from '../utils/hooks';
import { listItemCss, ListItemVariants } from '../shared/list-item';

import type { PolyProps, PolyRef } from '../utils/polymorphic';
import type { ForwardRefComponent } from '../utils/polymorphic';
import styles from './menu-list.module.css';

interface MenuListProps extends ComponentProps<typeof Flex> {}
Expand All @@ -20,38 +20,31 @@ export const MenuList = ({ flow = 'column', className, ...props }: MenuListProps
);
};

type MenuListItemProps<C extends ElementType> = PolyProps<
C,
ListItemVariants & { disabled?: boolean; active?: boolean }
>;
type MenuListItemComponent = <C extends ElementType = 'span'>(props: MenuListItemProps<C>) => ReactElement | null;

export const Item: MenuListItemComponent = forwardRef(
<C extends ElementType = 'a'>(
{ as, className, disabled, onKeyDown, active, ...props }: MenuListItemProps<C>,
ref: PolyRef<C>
) => {
const Component = as || 'a';
const onKeyDownHandler = useKeyboardHandles({
'Enter': (e) => e.currentTarget.click?.(),
' ': (e) => e.currentTarget.click?.(),
});
const handleKeyDown = useAllHandlers(onKeyDown, onKeyDownHandler);

return (
<RovingFocusGroup.Item asChild focusable={!disabled} active={active}>
<Component
{...props}
className={clsx(listItemCss(props), styles['menu-item'], className)}
aria-disabled={disabled}
aria-current={active}
role="treeitem"
onKeyDown={handleKeyDown}
ref={ref}
/>
</RovingFocusGroup.Item>
);
}
);
interface MenuListItemProps extends ListItemVariants {
disabled?: boolean;
active?: boolean;
}

export const Item = forwardRef(({ as: Component = 'a', className, disabled, onKeyDown, active, ...props }, ref) => {
const onKeyDownHandler = useKeyboardHandles({
'Enter': (e) => e.currentTarget.click?.(),
' ': (e) => e.currentTarget.click?.(),
});
const handleKeyDown = useAllHandlers(onKeyDown, onKeyDownHandler);

return (
<RovingFocusGroup.Item asChild focusable={!disabled} active={active}>
<Component
{...props}
className={clsx(listItemCss(props), styles['menu-item'], className)}
aria-disabled={disabled}
aria-current={active}
role="treeitem"
onKeyDown={handleKeyDown}
ref={ref}
/>
</RovingFocusGroup.Item>
);
}) as ForwardRefComponent<'a', MenuListItemProps>;

MenuList.Item = Item;
19 changes: 7 additions & 12 deletions src/lib/menu/menu.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
ComponentProps,
ElementType,
forwardRef,
ForwardRefExoticComponent,
ReactElement,
Expand All @@ -19,8 +18,6 @@ import { ListItem, ListItemVariants } from '../shared/list-item';
import { useIsomorphicLayoutEffect } from '../utils/hooks';
import { Presence } from '../shared/presence';

import type { LabelComponent, LabelProps } from '../form-field/label';
import type { PolyRef } from '../utils/polymorphic';
import styles from './menu.module.css';

interface MenuProps {
Expand Down Expand Up @@ -112,15 +109,13 @@ export const Separator = (props: ComponentProps<'div'>) => {
return <div {...props} className={clsx(styles.separator, props.className)} />;
};

const MenuLabel: LabelComponent = forwardRef(
<C extends ElementType = 'label'>(props: LabelProps<C>, ref: PolyRef<C>) => {
return (
<RdxMenu.Label asChild>
<Label {...props} ref={ref} />
</RdxMenu.Label>
);
}
);
const MenuLabel = forwardRef((props, ref) => {
return (
<RdxMenu.Label asChild>
<Label {...props} ref={ref} />
</RdxMenu.Label>
);
}) as typeof Label;

MenuRoot.List = List;
MenuRoot.Item = MenuItem;
Expand Down
16 changes: 6 additions & 10 deletions src/lib/shared/list-item.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { ElementType, forwardRef, ReactElement } from 'react';
import { forwardRef } from 'react';
import { classed as css, VariantProps } from '@tw-classed/core';
import { clsx } from 'clsx';
import { flexCss, FlexVariants } from '../flex/flex';
import type { PolyProps, PolyRef } from '../utils/polymorphic';
import type { ForwardRefComponent } from '../utils/polymorphic';

import styles from './list-item.module.css';

type ListItemProps<C extends ElementType> = PolyProps<C, ListItemVariants>;
type ListItemComponent = <C extends ElementType = 'span'>(props: ListItemProps<C>) => ReactElement | null;
interface ListItemProps extends ListItemVariants {}

export const ListItem: ListItemComponent = forwardRef(
<C extends ElementType = 'div'>({ as, className, ...props }: ListItemProps<C>, ref: PolyRef<C>) => {
const Component = as || 'div';
return <Component className={clsx(listItemCss(props), className)} {...props} ref={ref} />;
}
);
export const ListItem = forwardRef(({ as: Component = 'div', className, ...props }, ref) => {
return <Component className={clsx(listItemCss(props), className)} {...props} ref={ref} />;
}) as ForwardRefComponent<'div', ListItemProps>;

const listItemCssInner = css(styles['list-item'], flexCss, {
variants: {
Expand Down
21 changes: 9 additions & 12 deletions src/lib/text/text.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import { ElementType, forwardRef, ReactElement } from 'react';
import { CSSProperties, forwardRef } from 'react';
import { classed as css, VariantProps } from '@tw-classed/core';
import { clsx } from 'clsx';

import type { PolyProps, PolyRef } from '../utils/polymorphic';
import type { ForwardRefComponent } from '../utils/polymorphic';
import styles from './text.module.css';

type TextProps<C extends ElementType> = PolyProps<C, VariantProps<typeof textCss> & { lineClamp?: number }>;
type TextComponent = <C extends ElementType = 'span'>(props: TextProps<C>) => ReactElement | null;
interface TextProps extends VariantProps<typeof textCss> {
lineClamp?: number;
}

export const Text: TextComponent = forwardRef(
<C extends ElementType = 'span'>(
{ as, textStyle, tone, align, lineClamp, className, style, ...props }: TextProps<C>,
ref: PolyRef<C>
) => {
const Component = as || 'span';
export const Text = forwardRef(
({ as: Component = 'span', textStyle, tone, align, lineClamp, className, style, ...props }, ref) => {
return (
<Component
className={clsx(textCss({ textStyle, tone, align }), lineClamp && styles['line-clamp'], className)}
style={lineClamp ? { ...style, '--fx-text-lineClamp': lineClamp } : style}
style={lineClamp ? ({ ...style, '--fx-text-lineClamp': lineClamp } as CSSProperties) : style}
{...props}
ref={ref}
/>
);
}
);
) as ForwardRefComponent<'span', TextProps>;

export const textCss = css(styles.text, {
variants: {
Expand Down
17 changes: 1 addition & 16 deletions src/lib/utils/polymorphic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,6 @@

import type * as React from 'react';

type PolymorphicRef<C extends React.ElementType> = React.ComponentPropsWithRef<C>['ref'];

type AsProp<C extends React.ElementType> = {
as?: C;
};

type PropsToOmit<C extends React.ElementType, P> = keyof (AsProp<C> & P);

type PolymorphicComponentProp<C extends React.ElementType, Props = {}> = React.PropsWithChildren<Props & AsProp<C>> &
Omit<React.ComponentPropsWithoutRef<C>, PropsToOmit<C, Props>>;

type PolymorphicComponentPropWithRef<C extends React.ElementType, Props = {}> = PolymorphicComponentProp<C, Props> & {
ref?: PolymorphicRef<C>;
};

type Merge<P1 = {}, P2 = {}> = Omit<P1, keyof P2> & P2;

type ForwardRefExoticComponent<E, OwnProps> = React.ForwardRefExoticComponent<
Expand Down Expand Up @@ -71,4 +56,4 @@ interface ForwardRefComponent<
): React.ReactElement | null;
}

export type { PolymorphicComponentPropWithRef as PolyProps, PolymorphicRef as PolyRef, ForwardRefComponent };
export type { ForwardRefComponent };
11 changes: 0 additions & 11 deletions src/pages/components/TextField.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,6 @@ title: TextField
<TextField size="lg" variant="underlined" hint="Pretty variant" label="Underlined" placeholder="Large size" />
<TextField size="lg" variant="flat" placeholder="Large size" />
</Column>
<Column gap="md">
<TextField size="xl" label="Boxed" hint="Default variant" placeholder="Editable heading size" />
<TextField
size="xl"
variant="underlined"
hint="Pretty variant"
label="Underlined"
placeholder="Editable heading size"
/>
<TextField size="xl" variant="flat" placeholder="Editable heading size" />
</Column>
</Row>
```

Expand Down

1 comment on commit 7f313f9

@vercel
Copy link

@vercel vercel bot commented on 7f313f9 Dec 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

fxtrot-ui – ./

fxtrot-ui-lexswed.vercel.app
fxtrot-ui-git-main-lexswed.vercel.app
fxtrot-ui.vercel.app

Please sign in to comment.