Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui/system): slottable 개념 도입 #199

Merged
merged 3 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions packages/ui/system/src/create-polymorphic-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@ import {
Children,
type ComponentPropsWithoutRef,
type ElementType,
type ReactElement,
type ReactNode,
type Ref,
cloneElement,
createElement,
isValidElement,
} from 'react';
import { forwardRef } from './forward-ref';
import { Slottable, type SlottableProps } from './slottable';
import {
type ComponentWithPolymorphic,
type JsxElements,
type PolymorphicProps,
} from './types';

export function isSlottable(
child: ReactNode,
): child is ReactElement<SlottableProps> {
return isValidElement(child) && child.type === Slottable;
}

export type FavolinkComponent<Component extends ElementType> =
ComponentWithPolymorphic<Component, object>;

Expand All @@ -36,6 +45,43 @@ export function createPolymorphicComponent<Component extends ElementType>(
);
}

const childrenArray = Children.toArray(children);
const slottable = childrenArray.find(isSlottable);

if (slottable) {
const newElement = slottable.props.children;
const newChildren = childrenArray.map((child) => {
if (child === slottable) {
if (Children.count(newElement) > 1) {
return Children.only(null);
}

return isValidElement(newElement)
? ((newElement as ReactElement<{ children: ReactNode }>).props
.children as ReactNode)
: null;
} else {
return child;
}
});

return isValidElement(newElement)
? cloneElement(
newElement as ReactElement,
{
...mergeProps(restProps, newElement.props),
ref: ref
? composeRefs(
ref,
(newElement as ReactElement & { ref: Ref<any> }).ref,
)
: (newElement as ReactElement & { ref: Ref<any> }).ref,
},
newChildren,
)
: null;
}

const onlyChild = Children.only(children);

return isValidElement(onlyChild)
Expand Down
1 change: 1 addition & 0 deletions packages/ui/system/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from './create-polymorphic-component';
export * from './create-raw-style-props';
export * from './factory';
export * from './forward-ref';
export * from './slottable';
export * from './types';
11 changes: 11 additions & 0 deletions packages/ui/system/src/slottable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { type ReactNode } from 'react';

export type SlottableProps = {
children: ReactNode;
};

export function Slottable(props: SlottableProps) {
const { children } = props;

return children;
}
Loading