Skip to content
This repository has been archived by the owner on Jun 5, 2024. It is now read-only.

Commit

Permalink
TextField 옵션 추가 및 TextTab 바인딩 추가 (#89)
Browse files Browse the repository at this point in the history
* feat: add TextField options

- showHintOnFocusOnly, hideClearButton

* feat: TextField options ReScript bindings

* feat: TextTab export / add ReScript binding

* release
  • Loading branch information
Jaeho Lee authored Dec 12, 2022
1 parent f8a8d7f commit 1a0ee18
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 79 deletions.
7 changes: 7 additions & 0 deletions .changeset/three-coats-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@greenlabs/formula-components": patch
"@greenlabs/rescript-formula-components": patch
---

- feat: add TextField options (showHintOnFocusOnly, hideClearButton)
- feat: TextField options ReScript bindings
41 changes: 36 additions & 5 deletions packages/components-rescript/__tests__/Formula_test.res
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
open Formula

module TestTextContainer = {
@react.component
let make = (~className=?, ~children=?) => {
Expand All @@ -6,7 +8,6 @@ module TestTextContainer = {
}

let testText = () => {
open Formula
<>
<Text
variant=#body
Expand All @@ -31,7 +32,6 @@ let testText = () => {
}

let testIcon = () => {
open Formula
<>
<Icon.CalendarLineBold />
<Icon.CalendarLineRegular color=#"lightblue-90" />
Expand All @@ -43,15 +43,13 @@ let testIcon = () => {
}

let testDivider = () => {
open Formula
<>
<Divider />
<Divider className="some-className" variant=#large props={{"id": "id-of-divider"}} />
</>
}

let testButton = () => {
open Formula
<>
<Button.Container color=#primary size=#sm text="I'm ContainerButton" />
<Button.Container color=#"secondary-gray" size=#sm block=true text="I'm full width button" />
Expand All @@ -69,7 +67,6 @@ let testButton = () => {
}

let testTextField = () => {
open Formula
<>
<TextField />
<TextField _type=#password size=#large />
Expand All @@ -95,9 +92,43 @@ let testTextField = () => {
<input ?onChange id className ref={inputRef} />
}}
/>
<TextField
options={{
showHintOnFocusOnly: true,
}}
/>
</>
}

let textTextTab = () => {
<TextTab.List
rootProps={{"defaultValue": "a"}}
fullWidth={true}
onValueChange={_ => ()}
contents={<>
<TextTab.Content value="a"> {`this is a`->React.string} </TextTab.Content>
<TextTab.Content value="b"> {`this is b`->React.string} </TextTab.Content>
<TextTab.Content value="c"> {`this is c`->React.string} </TextTab.Content>
</>}>
<TextTab.Trigger title="텍스트 a" value="a" icon={Icon.ArrowDownLineBold.make} />
<TextTab.Trigger
title="텍스트 "
value="b"
badge={{
type_: #countSimple,
value: 9,
}}
/>
<TextTab.Trigger
value="c"
badge={{
type_: #simple,
}}>
<Icon.ArrowDownLineBold />
</TextTab.Trigger>
</TextTab.List>
}

let testCommon = () => {
<div style={ReactDOM.Style.make(~color=Formula.Theme.themeColors["blue-100"], ())} />
}
1 change: 1 addition & 0 deletions packages/components-rescript/src/Formula.res
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ module TextField = Formula__TextField
module Icon = Formula__Icon
module Divider = Formula__Divider
module Button = Formula__Button
module TextTab = Formula__TextTab
10 changes: 8 additions & 2 deletions packages/components-rescript/src/Formula__TextField.res
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ type textFieldComponentProps<'a> = {
disabled?: bool,
}

type options = {
showHintOnFocusOnly?: bool,
hideClearButton?: bool,
}

@module("@greenlabs/formula-components") @react.component
external make: (
~props: {..}=?,
Expand All @@ -24,9 +29,9 @@ external make: (
~_type: [#text | #password]=?,
~placeholder: string=?,
~prefix: React.element=?,
~prefixIcon: React.componentLike<{..}, React.element>=?,
~prefixIcon: React.componentLike<{..}, React.element>=?, // FIXME: Icon component type
~suffix: React.element=?,
~suffixIcon: React.componentLike<{..}, React.element>=?,
~suffixIcon: React.componentLike<{..}, React.element>=?, // FIXME: Icon component type
~titleText: string=?,
~hintText: string=?,
~state: [#normal | #error]=?,
Expand All @@ -35,4 +40,5 @@ external make: (
~onChange: ReactEvent.Form.t => unit=?,
~onFocus: ReactEvent.Focus.t => unit=?,
~ref: ReactDOM.Ref.t=?,
~options: options=?,
) => React.element = "TextField"
37 changes: 37 additions & 0 deletions packages/components-rescript/src/Formula__TextTab.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module List = {
@module("@greenlabs/formula-components") @react.component
external make: (
~props: {..}=?,
~rootProps: {..}=?, // TODO: RadixUI props
~contents: React.element=?,
~fullWidth: bool=?,
~onValueChange: string => unit=?,
~children: React.element,
~ref: ReactDOM.Ref.t=?,
) => React.element = "TextTab"
}

module Trigger = {
type badgeType = {
type_: [#count | #simple | #countSimple],
value?: int,
}

@module("@greenlabs/formula-components") @react.component
external make: (
~icon: React.componentLike<{..}, React.element>=?, // FIXME: Icon component type
~title: string=?,
~badge: badgeType=?,
~value: string,
~children: React.element=?,
) => React.element = "TextTab"
}

module Content = {
@module("@greenlabs/formula-components") @react.component
external make: (
~value: string,
~children: React.element=?,
~props: ReactDOM.domProps=?,
) => React.element = "TextTab"
}
119 changes: 67 additions & 52 deletions packages/components/src/Tab/TextTab/TextTab.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { PropsWithChildren, ReactNode } from "react"
import { useLayoutEffect, useRef, useState } from "react"
import {
forwardRef,
useLayoutEffect,
useRef,
useState,
useImperativeHandle,
} from "react"
import type { TabsProps } from "@radix-ui/react-tabs"
import { Root, TabsList } from "@radix-ui/react-tabs"
import {
Expand All @@ -25,61 +31,70 @@ interface ListProps {
onValueChange?: (value: string) => void
}
// todo: on resize
export const List = ({
children,
contents = null,
onValueChange,
fullWidth,
rootProps,
...props
}: PropsWithChildren<ListProps>) => {
const ref = useRef<HTMLDivElement>(null)
const [state, setState] = useState({ left: 0, width: 0 })
export const List = forwardRef<HTMLDivElement, PropsWithChildren<ListProps>>(
(
{ children, contents = null, onValueChange, fullWidth, rootProps },
forwardedRef
) => {
const ref = useRef<HTMLDivElement>(null)
const [state, setState] = useState({ left: 0, width: 0 })

useImperativeHandle(forwardedRef, () => ref.current as HTMLDivElement)

useLayoutEffect(() => {
const tabEl = ref.current?.querySelector("button")
if (tabEl) {
setState(extractIndicatorState(tabEl))
useLayoutEffect(() => {
const tabEl = ref.current?.querySelector("button")
if (tabEl) {
setState(extractIndicatorState(tabEl))
}
}, [])

const onValueChangeWrapped = (value: string) => {
onValueChange?.(value)
// indicator animation
const listEl = ref.current
const activeTabEl = listEl?.querySelector<TriggerHTMLType>(
'[data-state="active"]'
)
if (activeTabEl) {
setState(extractIndicatorState(activeTabEl))
}
}
}, [])

const onValueChangeWrapped = (value: string) => {
onValueChange?.(value)
// indicator animation
const listEl = ref.current
const activeTabEl = listEl?.querySelector<TriggerHTMLType>(
'[data-state="active"]'
return (
<Root
className={rootStyle}
onValueChange={onValueChangeWrapped}
{...rootProps}
>
<div className={listContainerStyle}>
<TabsList
className={`${listStyle} ${fullWidth ? classes.tabListFull : ""}`}
ref={ref}
>
{children}
</TabsList>
<div
className={indicatorStyle}
style={{
width: `${state.width}px`,
transform: `translate(${state.left}px, 1px)`,
}}
/>
</div>
{contents}
</Root>
)
if (activeTabEl) {
setState(extractIndicatorState(activeTabEl))
}
}

return (
<Root
className={rootStyle}
onValueChange={onValueChangeWrapped}
{...rootProps}
>
<div className={listContainerStyle}>
<TabsList
className={`${listStyle} ${fullWidth ? classes.tabListFull : ""}`}
ref={ref}
>
{children}
</TabsList>
<div
className={indicatorStyle}
style={{
width: `${state.width}px`,
transform: `translate(${state.left}px, 1px)`,
}}
/>
</div>
{contents}
</Root>
)
}
)

export { Trigger } from "./Trigger"
export { Content } from "@radix-ui/react-tabs"
import { Content as RadixTabsContent } from "@radix-ui/react-tabs"

export const Content = forwardRef<
HTMLDivElement,
{
value: string
children?: React.ReactNode
props?: React.RefAttributes<HTMLDivElement>
}
>(({ value, props }) => <RadixTabsContent value={value} {...props} />)
1 change: 0 additions & 1 deletion packages/components/src/Tab/index.tsx

This file was deleted.

18 changes: 15 additions & 3 deletions packages/components/src/TextField/TextField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const commonDisabled = createDisabledArgs([
"suffixIcon",
"onChange",
"onFocus",
"options",
])

const iconControlMapping = Object.entries(IconComponents).reduce(
Expand Down Expand Up @@ -156,7 +157,9 @@ Line.args = {
}
Line.argTypes = BoxOutline.argTypes

export const Textarea_and_Ref: ComponentStory<typeof TextField> = (args) => {
export const Textarea_and_Ref_Etc: ComponentStory<typeof TextField> = (
args
) => {
const ref = React.useRef<HTMLInputElement>(null)

React.useLayoutEffect(() => {
Expand Down Expand Up @@ -205,14 +208,23 @@ export const Textarea_and_Ref: ComponentStory<typeof TextField> = (args) => {
titleText="using `react-textarea-autosize` as `inputContainer`"
inputContainer={inputContainer}
/>
<br />
<TextField
{...args}
titleText="options.showHintOnFocusOnly | options.hideClearButton"
options={{
showHintOnFocusOnly: true,
hideClearButton: true,
}}
/>
</form>
)}
/>
)
}

Textarea_and_Ref.args = Overview.args
Textarea_and_Ref.argTypes = {
Textarea_and_Ref_Etc.args = Overview.args
Textarea_and_Ref_Etc.argTypes = {
...commonDisabled,
...controls,
}
Expand Down
Loading

0 comments on commit 1a0ee18

Please sign in to comment.