Skip to content

Commit

Permalink
Merge pull request #96 from openinfradev/feature-scroll-to-component
Browse files Browse the repository at this point in the history
Feature. Add ScrollToComponent API on all validatable Components
  • Loading branch information
Siyeop authored Apr 26, 2024
2 parents d3e3260 + d7e1a8e commit 42bd322
Show file tree
Hide file tree
Showing 20 changed files with 70 additions and 38 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tksui-components",
"version": "0.6.12",
"version": "0.6.14",
"private": false,
"type": "module",
"module": "lib/esm/index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ export interface TCheckboxGroupProps extends TBaseProps, TValidatorProps {

export interface TCheckboxGroupRef {
validate(): true | string,
scrollToComponent(): void,
}
14 changes: 8 additions & 6 deletions src/components/input/checkbox-group/TCheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {forwardRef, Ref, useCallback, useImperativeHandle, useMemo, useRef} from 'react';
import useValidator from '@/common/hook/UseValidator';
import {TCheckboxGroupProps, TCheckboxGroupRef, TCheckboxGroupValue} from './TCheckboxGroup.interface';
import {TCheckboxGroupProps, TCheckboxGroupRef, TCheckboxGroupValue, TCheckboxValue} from '@/components';
import TCheckbox from '../checkbox/TCheckbox';
import {TCheckboxValue} from '../checkbox/TCheckbox.interface';


const TCheckboxGroup = forwardRef((props: TCheckboxGroupProps, ref: Ref<TCheckboxGroupRef>) => {
Expand All @@ -14,6 +13,9 @@ const TCheckboxGroup = forwardRef((props: TCheckboxGroupProps, ref: Ref<TCheckbo

useImperativeHandle(ref, () => ({
validate() { return validator.validate(); },
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
rootRef?.current?.scrollIntoView(options);
},
}));

// endregion
Expand All @@ -24,10 +26,10 @@ const TCheckboxGroup = forwardRef((props: TCheckboxGroupProps, ref: Ref<TCheckbo
const rootClass = useMemo(() => {
const clazz: string[] = [];

if (props.className) clazz.push(props.className);
if (props.disabled) clazz.push('t-checkbox-group--disabled');
if (!validator.result) clazz.push('t-checkbox-group--failure');
if (validator.result && validator.message) clazz.push('t-checkbox-group--success');
if (props.className) { clazz.push(props.className); }
if (props.disabled) { clazz.push('t-checkbox-group--disabled'); }
if (!validator.result) { clazz.push('t-checkbox-group--failure'); }
if (validator.result && validator.message) { clazz.push('t-checkbox-group--success'); }

return clazz.join(' ');
}, [props.className, props.disabled, validator]);
Expand Down
1 change: 1 addition & 0 deletions src/components/input/checkbox/TCheckbox.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ export interface TCheckboxProps extends TValidatorProps, TBaseProps {
export interface TCheckboxRef {
focus(): void,
validate(): true | string,
scrollToComponent(): void,
}
5 changes: 4 additions & 1 deletion src/components/input/checkbox/TCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const TCheckbox = forwardRef((props: TCheckboxProps, ref: Ref<TCheckboxRef>) =>
useImperativeHandle(ref, () => ({
focus() { containerRef?.current?.focus(); },
validate() { return validator.validate(); },
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
rootRef?.current?.scrollIntoView(options);
},
}));

// endregion
Expand Down Expand Up @@ -89,7 +92,7 @@ const TCheckbox = forwardRef((props: TCheckboxProps, ref: Ref<TCheckboxRef>) =>
} else {
setStatus('uncheck');
}
}, [props.value, props.checked, props.indeterminate, props.positiveValue, props.readOnly]);
}, [props.value, props.checked, props.indeterminate, props.positiveValue]);

// endregion

Expand Down
1 change: 1 addition & 0 deletions src/components/input/date-picker/TDatePicker.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface TDatePickerRef {
open(): void,
validate(): true | string,
getDate(): string,
scrollToComponent(): void,
}

export interface TDatePickerBounds {
Expand Down
3 changes: 3 additions & 0 deletions src/components/input/date-picker/TDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const TDatePicker = forwardRef((props: TDatePickerProps, ref: Ref<TDatePickerRef
open() { dropHolderRef?.current?.open(); },
validate() { return validator.validate(); },
getDate() { return dateValue; },
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
rootRef?.current?.scrollIntoView(options);
},
}));

// endregion
Expand Down
1 change: 1 addition & 0 deletions src/components/input/dropdown/TDropdown.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ export interface TDropdownRef {
validate(): true | string,
manualValidate(result: boolean, message?: string): void,
clearValidation(): void,
scrollToComponent(): void,
}
3 changes: 3 additions & 0 deletions src/components/input/dropdown/TDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const TDropdown = forwardRef((props: TDropdownProps, ref: Ref<TDropdownRef>) =>
clearValidation() {
validator.clearValidation();
},
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
rootRef?.current?.scrollIntoView(options);
},
}));

// endregion
Expand Down
4 changes: 2 additions & 2 deletions src/components/input/number-field/TNumberField.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export interface TNumberFieldProps extends TBaseProps, TValidatorProps {


export interface TNumberFieldRef {
focus(): void,

focus(): void,
validate(): true | string,

manualValidate(result: boolean, message?: string): void,
scrollToComponent(): void,
}
9 changes: 6 additions & 3 deletions src/components/input/number-field/TNumberField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const TNumberField = forwardRef((props: TNumberFieldProps, ref: Ref<TNumberField
manualValidate(result: boolean, message?: string) {
validator.manualValidate(result, message);
},
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
inputRef?.current?.scrollIntoView(options);
},
}));

// endregion
Expand All @@ -47,7 +50,7 @@ const TNumberField = forwardRef((props: TNumberFieldProps, ref: Ref<TNumberField
const inputClass: string = useMemo((): string => {
const clazz: string[] = [];

if (props.disabled) clazz.push('t-number-field__container__input--disabled');
if (props.disabled) { clazz.push('t-number-field__container__input--disabled'); }

return clazz.join(' ');
}, [props.disabled]);
Expand Down Expand Up @@ -84,8 +87,8 @@ const TNumberField = forwardRef((props: TNumberFieldProps, ref: Ref<TNumberField
const rootStyle: CSSProperties = useMemo((): CSSProperties => {
let style: CSSProperties = {};

if (props.style) style = {...props.style};
if (props.width) style = {...style, width: props.width};
if (props.style) { style = {...props.style}; }
if (props.width) { style = {...style, width: props.width}; }

return style;
}, [props.style, props.width]);
Expand Down
1 change: 1 addition & 0 deletions src/components/input/radio-group/TRadioGroup.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ export interface TRadioGroupProps extends TBaseProps, TValidatorProps {

export interface TRadioGroupRef {
validate(): true | string,
scrollToComponent(): void,
}
16 changes: 9 additions & 7 deletions src/components/input/radio-group/TRadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import useValidator from '@/common/hook/UseValidator';


import TRadio from '../radio/TRadio';
import {TRadioGroupProps, TRadioGroupRef, TRadioGroupValue} from './TRadioGroup.interface';
import {TRadioValue} from '../radio/TRadio.interface';
import {TRadioGroupProps, TRadioGroupRef, TRadioGroupValue, TRadioValue} from '@/components';


const TRadioGroup = forwardRef((props: TRadioGroupProps, ref: Ref<TRadioGroupRef>) => {
Expand All @@ -17,6 +16,9 @@ const TRadioGroup = forwardRef((props: TRadioGroupProps, ref: Ref<TRadioGroupRef

useImperativeHandle(ref, () => ({
validate() { return validator.validate(); },
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
rootRef?.current?.scrollIntoView(options);
},
}));

// endregion
Expand All @@ -27,18 +29,18 @@ const TRadioGroup = forwardRef((props: TRadioGroupProps, ref: Ref<TRadioGroupRef
function getRootClass(): string {
const clazz: string[] = [];

if (props.className) clazz.push(props.className);
if (props.disabled) clazz.push('t-radio-group--disabled');
if (!validator.result) clazz.push('t-radio-group--failure');
if (validator.result && validator.message) clazz.push('t-radio-group--success');
if (props.className) { clazz.push(props.className); }
if (props.disabled) { clazz.push('t-radio-group--disabled'); }
if (!validator.result) { clazz.push('t-radio-group--failure'); }
if (validator.result && validator.message) { clazz.push('t-radio-group--success'); }

return clazz.join(' ');
}

function getRootStyle(): CSSProperties {
let style: CSSProperties = {};

if (props.style) style = {...props.style};
if (props.style) { style = {...props.style}; }

return style;
}
Expand Down
1 change: 1 addition & 0 deletions src/components/input/text-area/TTextArea.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ export interface TTextAreaProps extends TValidatorProps, TBaseProps {
export interface TTextAreaRef {
focus(): void,
validate(): true | string,
scrollToComponent(): void,
}
18 changes: 11 additions & 7 deletions src/components/input/text-area/TTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const TTextArea = forwardRef((props: TTextAreaProps, ref: Ref<TTextAreaRef>) =>
validate() {
return validator.validate();
},
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
textareaRef?.current?.scrollIntoView(options);
},

}));

// endregion
Expand Down Expand Up @@ -68,12 +72,12 @@ const TTextArea = forwardRef((props: TTextAreaProps, ref: Ref<TTextAreaRef>) =>
const rootClass = useMemo((): string => {
const clazz: string[] = [];

if (props.className) clazz.push(props.className);
if (props.className) { clazz.push(props.className); }

if (props.disabled) clazz.push('t-text-area--disabled');
if (!validator.result) clazz.push('t-text-area--failure');
if (props.disabled) { clazz.push('t-text-area--disabled'); }
if (!validator.result) { clazz.push('t-text-area--failure'); }
if (hasFocus) { clazz.push('t-text-area--focused'); }
if (validator.result && validator.message) clazz.push('t-text-area--success');
if (validator.result && validator.message) { clazz.push('t-text-area--success'); }

clazz.push(`t-text-area--${props.type}`);

Expand All @@ -91,8 +95,8 @@ const TTextArea = forwardRef((props: TTextAreaProps, ref: Ref<TTextAreaRef>) =>
const rootStyle = useMemo((): CSSProperties => {
let style: CSSProperties = {};

if (props.style) style = {...props.style};
if (props.width) style = {...style, width: props.width};
if (props.style) { style = {...props.style}; }
if (props.width) { style = {...style, width: props.width}; }

return style;
}, [props.style, props.width]);
Expand All @@ -101,7 +105,7 @@ const TTextArea = forwardRef((props: TTextAreaProps, ref: Ref<TTextAreaRef>) =>
const textAreaClass = useMemo((): string => {
const clazz: string[] = [];

if (props.disabled) clazz.push('t-text-area__container__input--disabled');
if (props.disabled) { clazz.push('t-text-area__container__input--disabled'); }

return clazz.join(' ');
}, [props.disabled]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export interface TTextArrayFieldRef {
clearValidation(): void,
getValidateResult(): boolean,
getValidateMessage(): string,
scrollToComponent(): void,
}
6 changes: 5 additions & 1 deletion src/components/input/text-array-field/TTextArrayField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const TTextArrayField = forwardRef((props: TTextArrayFieldProps, ref: Ref<TTextA

const [currentInput, setCurrentInput] = useState<string>('');

const rootRef = useRef<HTMLDivElement>(null);
const textFieldRef = useRef<TTextFieldRef>(null);

useImperativeHandle(ref, () => ({
Expand All @@ -31,6 +32,9 @@ const TTextArrayField = forwardRef((props: TTextArrayFieldProps, ref: Ref<TTextA
getValidateResult(): boolean {
return validator.result;
},
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
rootRef?.current?.scrollIntoView(options);
},
}));


Expand Down Expand Up @@ -116,7 +120,7 @@ const TTextArrayField = forwardRef((props: TTextArrayFieldProps, ref: Ref<TTextA
// endregion

return (
<div className={`t-text-array-field ${rootClass}`} style={rootStyle} id={props.id} data-testid={'text-field-root'}>
<div className={`t-text-array-field ${rootClass}`} style={rootStyle} id={props.id} data-testid={'text-field-root'} ref={rootRef}>

<span className={'t-text-array-field__input-container'} onClick={onClickInputContainer}>
{
Expand Down
1 change: 1 addition & 0 deletions src/components/input/text-field/TTextField.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface TTextFieldProps extends TValidatorProps, TBaseProps {

export interface TTextFieldRef {
focus(): void,
scrollToComponent(): void,
blur(): void,
validate(): true | string,
manualValidate(result: boolean, message?: string): void,
Expand Down
4 changes: 4 additions & 0 deletions src/components/input/text-field/TTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const TTextField = forwardRef((props: TTextFieldProps, ref: Ref<TTextFieldRef>)
inputRef?.current?.focus();
textareaRef?.current?.focus();
},
scrollToComponent(options: ScrollIntoViewOptions = {behavior: 'smooth', block: 'center'}) {
inputRef?.current?.scrollIntoView(options);
textareaRef?.current?.scrollIntoView(options);
},
blur() {
inputRef?.current?.blur();
textareaRef?.current?.blur();
Expand Down
16 changes: 6 additions & 10 deletions stories/components/input/text-field/TTextField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,6 @@ const ValidationTemplate = (args: TTextFieldProps) => {
const textField2 = useInputState('');
const textField3 = useInputState('');
const textField4 = useInputState('');
const textField5 = useInputState('');
const textField6 = useInputState('');

const [textField1Ref, textField2Ref, textField3Ref, textField4Ref, textField5Ref, textField6Ref] = useRefs(6);

Expand All @@ -169,8 +167,6 @@ const ValidationTemplate = (args: TTextFieldProps) => {
textField2Ref.current.validate();
textField3Ref.current.validate();
textField4Ref.current.validate();
textField5Ref.current.validate();
textField6Ref.current.validate();
};

return (<>
Expand All @@ -196,8 +192,8 @@ const ValidationTemplate = (args: TTextFieldProps) => {
rule.required(),
rule.lengthBetween(3, 12),
]}
{...textField1}
ref={textField1Ref}
{...textField2}
ref={textField2Ref}
placeholder={'값을 입력해 주세요'}
counter={12}
dense
Expand All @@ -210,8 +206,8 @@ const ValidationTemplate = (args: TTextFieldProps) => {
),
rule.lengthBetween(3, 12),
]}
{...textField2}
ref={textField2Ref}
{...textField3}
ref={textField3Ref}
counter={12}
/>
<TTextField {...args}
Expand All @@ -221,8 +217,8 @@ const ValidationTemplate = (args: TTextFieldProps) => {
rule.lengthBetween(3, 12),
]}
counter={12}
{...textField3}
ref={textField3Ref}
{...textField4}
ref={textField4Ref}
successMessage={'사용할 수 있는 아이디입니다'}
/>
</div>
Expand Down

0 comments on commit 42bd322

Please sign in to comment.