컴포넌트 추가방식 변경
This commit is contained in:
93
frontend/lib/registry/components/slider-basic/README.md
Normal file
93
frontend/lib/registry/components/slider-basic/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# SliderBasic 컴포넌트
|
||||
|
||||
slider-basic 컴포넌트입니다
|
||||
|
||||
## 개요
|
||||
|
||||
- **ID**: `slider-basic`
|
||||
- **카테고리**: input
|
||||
- **웹타입**: number
|
||||
- **작성자**: Developer
|
||||
- **버전**: 1.0.0
|
||||
|
||||
## 특징
|
||||
|
||||
- ✅ 자동 등록 시스템
|
||||
- ✅ 타입 안전성
|
||||
- ✅ Hot Reload 지원
|
||||
- ✅ 설정 패널 제공
|
||||
- ✅ 반응형 디자인
|
||||
|
||||
## 사용법
|
||||
|
||||
### 기본 사용법
|
||||
|
||||
```tsx
|
||||
import { SliderBasicComponent } from "@/lib/registry/components/slider-basic";
|
||||
|
||||
<SliderBasicComponent
|
||||
component={{
|
||||
id: "my-slider-basic",
|
||||
type: "widget",
|
||||
webType: "number",
|
||||
position: { x: 100, y: 100, z: 1 },
|
||||
size: { width: 200, height: 36 },
|
||||
config: {
|
||||
// 설정값들
|
||||
}
|
||||
}}
|
||||
isDesignMode={false}
|
||||
/>
|
||||
```
|
||||
|
||||
### 설정 옵션
|
||||
|
||||
| 속성 | 타입 | 기본값 | 설명 |
|
||||
|------|------|--------|------|
|
||||
| min | number | - | 최소값 |
|
||||
| max | number | - | 최대값 |
|
||||
| step | number | 1 | 증감 단위 |
|
||||
| disabled | boolean | false | 비활성화 여부 |
|
||||
| required | boolean | false | 필수 입력 여부 |
|
||||
| readonly | boolean | false | 읽기 전용 여부 |
|
||||
|
||||
## 이벤트
|
||||
|
||||
- `onChange`: 값 변경 시
|
||||
- `onFocus`: 포커스 시
|
||||
- `onBlur`: 포커스 해제 시
|
||||
- `onClick`: 클릭 시
|
||||
|
||||
## 스타일링
|
||||
|
||||
컴포넌트는 다음과 같은 스타일 옵션을 제공합니다:
|
||||
|
||||
- `variant`: "default" | "outlined" | "filled"
|
||||
- `size`: "sm" | "md" | "lg"
|
||||
|
||||
## 예시
|
||||
|
||||
```tsx
|
||||
// 기본 예시
|
||||
<SliderBasicComponent
|
||||
component={{
|
||||
id: "sample-slider-basic",
|
||||
config: {
|
||||
placeholder: "입력하세요",
|
||||
required: true,
|
||||
variant: "outlined"
|
||||
}
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## 개발자 정보
|
||||
|
||||
- **생성일**: 2025-09-11
|
||||
- **CLI 명령어**: `node scripts/create-component.js slider-basic --category=input --webType=number`
|
||||
- **경로**: `lib/registry/components/slider-basic/`
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [컴포넌트 시스템 가이드](../../docs/컴포넌트_시스템_가이드.md)
|
||||
- [개발자 문서](https://docs.example.com/components/slider-basic)
|
||||
@@ -0,0 +1,146 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { ComponentRendererProps } from "@/types/component";
|
||||
import { SliderBasicConfig } from "./types";
|
||||
|
||||
export interface SliderBasicComponentProps extends ComponentRendererProps {
|
||||
config?: SliderBasicConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* SliderBasic 컴포넌트
|
||||
* slider-basic 컴포넌트입니다
|
||||
*/
|
||||
export const SliderBasicComponent: React.FC<SliderBasicComponentProps> = ({
|
||||
component,
|
||||
isDesignMode = false,
|
||||
isSelected = false,
|
||||
onClick,
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
config,
|
||||
className,
|
||||
style,
|
||||
...props
|
||||
}) => {
|
||||
// 컴포넌트 설정
|
||||
const componentConfig = {
|
||||
...config,
|
||||
...component.config,
|
||||
} as SliderBasicConfig;
|
||||
|
||||
// 스타일 계산 (위치는 RealtimePreviewDynamic에서 처리하므로 제외)
|
||||
const componentStyle: React.CSSProperties = {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
...component.style,
|
||||
...style,
|
||||
};
|
||||
|
||||
// 디자인 모드 스타일
|
||||
if (isDesignMode) {
|
||||
componentStyle.border = "1px dashed #cbd5e1";
|
||||
componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1";
|
||||
}
|
||||
|
||||
// 이벤트 핸들러
|
||||
const handleClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onClick?.();
|
||||
};
|
||||
|
||||
// DOM에 전달하면 안 되는 React-specific props 필터링
|
||||
const {
|
||||
selectedScreen,
|
||||
onZoneComponentDrop,
|
||||
onZoneClick,
|
||||
componentConfig: _componentConfig,
|
||||
component: _component,
|
||||
isSelected: _isSelected,
|
||||
onClick: _onClick,
|
||||
onDragStart: _onDragStart,
|
||||
onDragEnd: _onDragEnd,
|
||||
size: _size,
|
||||
position: _position,
|
||||
style: _style,
|
||||
...domProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div style={componentStyle} className={className} {...domProps}>
|
||||
{/* 라벨 렌더링 */}
|
||||
{component.label && (
|
||||
<label
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "-25px",
|
||||
left: "0px",
|
||||
fontSize: component.style?.labelFontSize || "14px",
|
||||
color: component.style?.labelColor || "#374151",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
{component.label}
|
||||
{component.required && <span style={{ color: "#ef4444" }}>*</span>}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "12px",
|
||||
padding: "8px",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
min={componentConfig.min || 0}
|
||||
max={componentConfig.max || 100}
|
||||
step={componentConfig.step || 1}
|
||||
value={component.value || componentConfig.min || 0}
|
||||
disabled={componentConfig.disabled || false}
|
||||
required={componentConfig.required || false}
|
||||
style={{
|
||||
width: "70%",
|
||||
height: "6px",
|
||||
outline: "none",
|
||||
borderRadius: "3px",
|
||||
background: "#e5e7eb",
|
||||
accentColor: "#3b82f6",
|
||||
}}
|
||||
onChange={(e) => {
|
||||
if (component.onChange) {
|
||||
component.onChange(e.target.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
width: "30%",
|
||||
textAlign: "center",
|
||||
fontSize: "14px",
|
||||
color: "#374151",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
{component.value || componentConfig.min || 0}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* SliderBasic 래퍼 컴포넌트
|
||||
* 추가적인 로직이나 상태 관리가 필요한 경우 사용
|
||||
*/
|
||||
export const SliderBasicWrapper: React.FC<SliderBasicComponentProps> = (props) => {
|
||||
return <SliderBasicComponent {...props} />;
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { SliderBasicConfig } from "./types";
|
||||
|
||||
export interface SliderBasicConfigPanelProps {
|
||||
config: SliderBasicConfig;
|
||||
onChange: (config: Partial<SliderBasicConfig>) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* SliderBasic 설정 패널
|
||||
* 컴포넌트의 설정값들을 편집할 수 있는 UI 제공
|
||||
*/
|
||||
export const SliderBasicConfigPanel: React.FC<SliderBasicConfigPanelProps> = ({
|
||||
config,
|
||||
onChange,
|
||||
}) => {
|
||||
const handleChange = (key: keyof SliderBasicConfig, value: any) => {
|
||||
onChange({ [key]: value });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="text-sm font-medium">
|
||||
slider-basic 설정
|
||||
</div>
|
||||
|
||||
{/* 숫자 관련 설정 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="min">최소값</Label>
|
||||
<Input
|
||||
id="min"
|
||||
type="number"
|
||||
value={config.min || ""}
|
||||
onChange={(e) => handleChange("min", parseFloat(e.target.value) || undefined)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="max">최대값</Label>
|
||||
<Input
|
||||
id="max"
|
||||
type="number"
|
||||
value={config.max || ""}
|
||||
onChange={(e) => handleChange("max", parseFloat(e.target.value) || undefined)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="step">단계</Label>
|
||||
<Input
|
||||
id="step"
|
||||
type="number"
|
||||
value={config.step || 1}
|
||||
onChange={(e) => handleChange("step", parseFloat(e.target.value) || 1)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 공통 설정 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="disabled">비활성화</Label>
|
||||
<Checkbox
|
||||
id="disabled"
|
||||
checked={config.disabled || false}
|
||||
onCheckedChange={(checked) => handleChange("disabled", checked)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="required">필수 입력</Label>
|
||||
<Checkbox
|
||||
id="required"
|
||||
checked={config.required || false}
|
||||
onCheckedChange={(checked) => handleChange("required", checked)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="readonly">읽기 전용</Label>
|
||||
<Checkbox
|
||||
id="readonly"
|
||||
checked={config.readonly || false}
|
||||
onCheckedChange={(checked) => handleChange("readonly", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { AutoRegisteringComponentRenderer } from "../../AutoRegisteringComponentRenderer";
|
||||
import { SliderBasicDefinition } from "./index";
|
||||
import { SliderBasicComponent } from "./SliderBasicComponent";
|
||||
|
||||
/**
|
||||
* SliderBasic 렌더러
|
||||
* 자동 등록 시스템을 사용하여 컴포넌트를 레지스트리에 등록
|
||||
*/
|
||||
export class SliderBasicRenderer extends AutoRegisteringComponentRenderer {
|
||||
static componentDefinition = SliderBasicDefinition;
|
||||
|
||||
render(): React.ReactElement {
|
||||
return <SliderBasicComponent {...this.props} renderer={this} />;
|
||||
}
|
||||
|
||||
/**
|
||||
* 컴포넌트별 특화 메서드들
|
||||
*/
|
||||
|
||||
// number 타입 특화 속성 처리
|
||||
protected getSliderBasicProps() {
|
||||
const baseProps = this.getWebTypeProps();
|
||||
|
||||
// number 타입에 특화된 추가 속성들
|
||||
return {
|
||||
...baseProps,
|
||||
// 여기에 number 타입 특화 속성들 추가
|
||||
};
|
||||
}
|
||||
|
||||
// 값 변경 처리
|
||||
protected handleValueChange = (value: any) => {
|
||||
this.updateComponent({ value });
|
||||
};
|
||||
|
||||
// 포커스 처리
|
||||
protected handleFocus = () => {
|
||||
// 포커스 로직
|
||||
};
|
||||
|
||||
// 블러 처리
|
||||
protected handleBlur = () => {
|
||||
// 블러 로직
|
||||
};
|
||||
}
|
||||
|
||||
// 자동 등록 실행
|
||||
SliderBasicRenderer.registerSelf();
|
||||
|
||||
// Hot Reload 지원 (개발 모드)
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
SliderBasicRenderer.enableHotReload();
|
||||
}
|
||||
44
frontend/lib/registry/components/slider-basic/config.ts
Normal file
44
frontend/lib/registry/components/slider-basic/config.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
"use client";
|
||||
|
||||
import { SliderBasicConfig } from "./types";
|
||||
|
||||
/**
|
||||
* SliderBasic 컴포넌트 기본 설정
|
||||
*/
|
||||
export const SliderBasicDefaultConfig: SliderBasicConfig = {
|
||||
min: 0,
|
||||
max: 999999,
|
||||
step: 1,
|
||||
|
||||
// 공통 기본값
|
||||
disabled: false,
|
||||
required: false,
|
||||
readonly: false,
|
||||
variant: "default",
|
||||
size: "md",
|
||||
};
|
||||
|
||||
/**
|
||||
* SliderBasic 컴포넌트 설정 스키마
|
||||
* 유효성 검사 및 타입 체크에 사용
|
||||
*/
|
||||
export const SliderBasicConfigSchema = {
|
||||
min: { type: "number" },
|
||||
max: { type: "number" },
|
||||
step: { type: "number", default: 1, min: 0.01 },
|
||||
|
||||
// 공통 스키마
|
||||
disabled: { type: "boolean", default: false },
|
||||
required: { type: "boolean", default: false },
|
||||
readonly: { type: "boolean", default: false },
|
||||
variant: {
|
||||
type: "enum",
|
||||
values: ["default", "outlined", "filled"],
|
||||
default: "default"
|
||||
},
|
||||
size: {
|
||||
type: "enum",
|
||||
values: ["sm", "md", "lg"],
|
||||
default: "md"
|
||||
},
|
||||
};
|
||||
42
frontend/lib/registry/components/slider-basic/index.ts
Normal file
42
frontend/lib/registry/components/slider-basic/index.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { createComponentDefinition } from "../../utils/createComponentDefinition";
|
||||
import { ComponentCategory } from "@/types/component";
|
||||
import type { WebType } from "@/types/screen";
|
||||
import { SliderBasicWrapper } from "./SliderBasicComponent";
|
||||
import { SliderBasicConfigPanel } from "./SliderBasicConfigPanel";
|
||||
import { SliderBasicConfig } from "./types";
|
||||
|
||||
/**
|
||||
* SliderBasic 컴포넌트 정의
|
||||
* slider-basic 컴포넌트입니다
|
||||
*/
|
||||
export const SliderBasicDefinition = createComponentDefinition({
|
||||
id: "slider-basic",
|
||||
name: "슬라이더",
|
||||
nameEng: "SliderBasic Component",
|
||||
description: "범위 값 선택을 위한 슬라이더 컴포넌트",
|
||||
category: ComponentCategory.INPUT,
|
||||
webType: "number",
|
||||
component: SliderBasicWrapper,
|
||||
defaultConfig: {
|
||||
min: 0,
|
||||
max: 999999,
|
||||
step: 1,
|
||||
},
|
||||
defaultSize: { width: 200, height: 36 },
|
||||
configPanel: SliderBasicConfigPanel,
|
||||
icon: "Edit",
|
||||
tags: [],
|
||||
version: "1.0.0",
|
||||
author: "Developer",
|
||||
documentation: "https://docs.example.com/components/slider-basic",
|
||||
});
|
||||
|
||||
// 타입 내보내기
|
||||
export type { SliderBasicConfig } from "./types";
|
||||
|
||||
// 컴포넌트 내보내기
|
||||
export { SliderBasicComponent } from "./SliderBasicComponent";
|
||||
export { SliderBasicRenderer } from "./SliderBasicRenderer";
|
||||
48
frontend/lib/registry/components/slider-basic/types.ts
Normal file
48
frontend/lib/registry/components/slider-basic/types.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import { ComponentConfig } from "@/types/component";
|
||||
|
||||
/**
|
||||
* SliderBasic 컴포넌트 설정 타입
|
||||
*/
|
||||
export interface SliderBasicConfig extends ComponentConfig {
|
||||
// 숫자 관련 설정
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
|
||||
// 공통 설정
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
readonly?: boolean;
|
||||
placeholder?: string;
|
||||
helperText?: string;
|
||||
|
||||
// 스타일 관련
|
||||
variant?: "default" | "outlined" | "filled";
|
||||
size?: "sm" | "md" | "lg";
|
||||
|
||||
// 이벤트 관련
|
||||
onChange?: (value: any) => void;
|
||||
onFocus?: () => void;
|
||||
onBlur?: () => void;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* SliderBasic 컴포넌트 Props 타입
|
||||
*/
|
||||
export interface SliderBasicProps {
|
||||
id?: string;
|
||||
name?: string;
|
||||
value?: any;
|
||||
config?: SliderBasicConfig;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
|
||||
// 이벤트 핸들러
|
||||
onChange?: (value: any) => void;
|
||||
onFocus?: () => void;
|
||||
onBlur?: () => void;
|
||||
onClick?: () => void;
|
||||
}
|
||||
Reference in New Issue
Block a user