@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.39 → 1.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/all-component-tools.js +2 -0
- package/build/components/data/icon-names.generated.js +341 -0
- package/build/components/data/icon-names.js +32 -16
- package/build/components/examples/opsnow-common-chart-examples-data.js +73 -78
- package/build/components/examples/opsnow-common-forms-examples-data.js +1 -11
- package/build/components/examples/opsnow-common-grid-examples-data.js +271 -20
- package/build/components/examples/opsnow-common-layout-examples-data.js +12 -13
- package/build/components/examples/opsnow-common-popup-examples-data.js +14 -28
- package/build/components/examples/opsnow-common-progress-examples-data.js +0 -5
- package/build/components/examples/opsnow-common-stepper-examples-data.js +2 -3
- package/build/components/examples/opsnow-common-storage-examples-data.js +23 -4
- package/build/components/examples/opsnow-common-tooltip-examples-data.js +1 -21
- package/build/components/opsnow-common-calendar.js +36 -15
- package/build/components/opsnow-common-chart.js +213 -132
- package/build/components/opsnow-common-coach-mark.js +3 -2
- package/build/components/opsnow-common-data-status.js +17 -11
- package/build/components/opsnow-common-dropdown.js +80 -0
- package/build/components/opsnow-common-examples.js +4 -2
- package/build/components/opsnow-common-file-upload.js +4 -1
- package/build/components/opsnow-common-forms.js +73 -36
- package/build/components/opsnow-common-grid.js +72 -29
- package/build/components/opsnow-common-icons.js +23 -39
- package/build/components/opsnow-common-jsx-helper.js +36 -0
- package/build/components/opsnow-common-layout.js +66 -25
- package/build/components/opsnow-common-notification.js +3 -2
- package/build/components/opsnow-common-pagination.js +4 -4
- package/build/components/opsnow-common-popup.js +12 -11
- package/build/components/opsnow-common-progress.js +10 -16
- package/build/components/opsnow-common-select.js +26 -13
- package/build/components/opsnow-common-stepper.js +30 -7
- package/build/components/opsnow-common-tab.js +5 -3
- package/build/components/opsnow-common-toast-popup.js +1 -0
- package/build/components/opsnow-common-tooltip.js +44 -46
- package/build/components/opsnow-common-typography.js +11 -5
- package/build/components/opsnow-common-validate-props.js +0 -0
- package/build/index.js +2 -0
- package/package.json +2 -1
|
@@ -47,11 +47,10 @@ export const CircleProgressSchema = BaseProgressSchema.extend({
|
|
|
47
47
|
loadingDots: z
|
|
48
48
|
.object({
|
|
49
49
|
dotSize: z.number().describe("도트 크기"),
|
|
50
|
-
dotIndex: z.number().describe("도트 인덱스"),
|
|
51
50
|
})
|
|
52
51
|
.partial()
|
|
53
52
|
.optional()
|
|
54
|
-
.describe("도트 형태 일때 도트 속성(dotSize
|
|
53
|
+
.describe("도트 형태 일때 도트 속성 (dotSize — 기본 8)"),
|
|
55
54
|
open: z.boolean().default(false).describe("open, setOpen useState 사용 여부"),
|
|
56
55
|
isFullScreen: z.boolean().default(false).describe("전체 화면 표시 여부"),
|
|
57
56
|
}).describe("단일 진행률인 경우 사용");
|
|
@@ -64,8 +63,8 @@ export function createProgressComponent() {
|
|
|
64
63
|
- 도트형태: 점(●)이 여러 개, 진행률 숫자/원형 바 없음(하나의 컴포넌트에 점 세개)
|
|
65
64
|
- 원형: 하나의 원, 진행률 숫자/텍스트/원형 바가 있음(앙에 숫자/텍스트/원형 바가 있으면 무조건 원형)
|
|
66
65
|
**주의사항:**
|
|
67
|
-
- 도트 형태를 사용하는 경우, <OpsnowCommonLoading loadingDots dotSize={8}/> 와 같이 loadingDots, dotSize
|
|
68
|
-
- 금지 : isLoadingDots = { dotSize: 8
|
|
66
|
+
- 도트 형태를 사용하는 경우, <OpsnowCommonLoading loadingDots dotSize={8}/> 와 같이 loadingDots, dotSize와 한꺼번에 묶어서 사용하지 않음
|
|
67
|
+
- 금지 : isLoadingDots = { dotSize: 8 } - 해당 예시처럼 사용 금지
|
|
69
68
|
**import:**
|
|
70
69
|
\`\`\`javascript
|
|
71
70
|
import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader';
|
|
@@ -97,13 +96,11 @@ export function createProgressComponent() {
|
|
|
97
96
|
if (args.isFullScreen)
|
|
98
97
|
props.push(`isFullScreen`);
|
|
99
98
|
if (args.loadingDots) {
|
|
100
|
-
if (args.loadingDots.dotSize
|
|
99
|
+
if (args.loadingDots.dotSize) {
|
|
101
100
|
props.push("loadingDots");
|
|
102
101
|
}
|
|
103
102
|
if (args.loadingDots?.dotSize)
|
|
104
103
|
props.push(`dotSize={${args.loadingDots.dotSize}}`);
|
|
105
|
-
if (args.loadingDots?.dotIndex)
|
|
106
|
-
props.push(`index={${args.loadingDots.dotIndex}}`);
|
|
107
104
|
}
|
|
108
105
|
// 컴포넌트 코드 생성
|
|
109
106
|
let componentCode = `
|
|
@@ -125,10 +122,10 @@ export function createProgressComponent() {
|
|
|
125
122
|
name: "createProgressLine",
|
|
126
123
|
description: `진행률 컴포넌트 생성 - 단일 진행률(%)을 라인 형태로 표시를 위한 컴포넌트 생성(라인, 바 형태)
|
|
127
124
|
**import:**
|
|
128
|
-
\`\`\`javascript
|
|
125
|
+
\`\`\`javascript
|
|
129
126
|
import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader';
|
|
130
127
|
const { OpsnowCommonProgress } = useCommonComponents();
|
|
131
|
-
|
|
128
|
+
\`\`\``,
|
|
132
129
|
parameters: LineProgressSchema,
|
|
133
130
|
handler: async (args) => {
|
|
134
131
|
let functionDefinitions = ``;
|
|
@@ -142,18 +139,15 @@ export function createProgressComponent() {
|
|
|
142
139
|
}
|
|
143
140
|
let componentCode = "";
|
|
144
141
|
const props = [];
|
|
145
|
-
props.push(`value={${args.percent}}`);
|
|
146
142
|
if (args.variant)
|
|
147
143
|
props.push(`variant="${args.variant}"`);
|
|
148
|
-
if (args.
|
|
149
|
-
props.push(`value
|
|
144
|
+
if (args.valueBuffer) {
|
|
145
|
+
props.push(`value={progress}`);
|
|
150
146
|
props.push(`valueBuffer={buffer}`);
|
|
151
147
|
}
|
|
152
|
-
else if (args.percent) {
|
|
153
|
-
props.push(`value
|
|
148
|
+
else if (args.percent !== undefined) {
|
|
149
|
+
props.push(`value={${args.percent}}`);
|
|
154
150
|
}
|
|
155
|
-
if (args.size)
|
|
156
|
-
props.push(`size="${args.size}"`);
|
|
157
151
|
if (args.showInfo)
|
|
158
152
|
props.push(`label`);
|
|
159
153
|
if (args.strokeColor)
|
|
@@ -2,17 +2,18 @@ import { z } from "zod";
|
|
|
2
2
|
// Select 컴포넌트 관련 스키마 정의
|
|
3
3
|
export const SelectSchema = z.object({
|
|
4
4
|
items: z.array(z.object({
|
|
5
|
-
value: z.string(),
|
|
5
|
+
value: z.union([z.string(), z.number()]),
|
|
6
6
|
label: z.any(), // string | JSX 가능
|
|
7
|
-
|
|
8
|
-
})).describe("셀렉트 옵션 목록"),
|
|
7
|
+
})).describe("셀렉트 옵션 목록 [{ value, label }] — 항목별 disabled는 지원하지 않음(무시됨)."),
|
|
9
8
|
value: z.any().optional().describe("선택된 값(단일/다중)"),
|
|
10
9
|
multiple: z.boolean().optional().default(false).describe("다중 선택 가능 여부"),
|
|
11
10
|
placeholder: z.string().optional().describe("플레이스홀더 텍스트"),
|
|
12
|
-
|
|
11
|
+
label: z.string().optional().describe("선택값 앞에 '라벨:' 접두로 표시되는 라벨 텍스트"),
|
|
12
|
+
variant: z.enum(["standard", "outlined", "filled", "noLine", "emUnderline"]).optional().describe("셀렉트 variant"),
|
|
13
13
|
size: z.enum(["small", "medium"]).optional().describe("셀렉트 크기"),
|
|
14
14
|
error: z.boolean().optional().default(false).describe("에러 상태"),
|
|
15
|
-
disabled: z.boolean().optional().default(false).describe("비활성화 여부")
|
|
15
|
+
disabled: z.boolean().optional().default(false).describe("비활성화 여부"),
|
|
16
|
+
copilotId: z.string().optional().describe("Copilot 연동 ID — Copilot 매니페스트의 bind.copilotId와 매칭되어 AI가 이 컨트롤을 조작할 수 있게 함. useCommonComponents()로 받은 컴포넌트에서만 동작(로더 HOC가 소비 후 제거)"),
|
|
16
17
|
});
|
|
17
18
|
// Autocomplete Select 컴포넌트 관련 스키마 정의
|
|
18
19
|
export const AutocompleteSelectSchema = z.object({
|
|
@@ -24,10 +25,13 @@ export const AutocompleteSelectSchema = z.object({
|
|
|
24
25
|
disabled: z.boolean().optional().default(false)
|
|
25
26
|
})).describe("오토컴플리트 옵션 목록"),
|
|
26
27
|
value: z.any().optional().describe("선택된 값/값들 (단일/다중)"),
|
|
27
|
-
multiple: z.boolean().optional().default(false).describe("다중 선택 가능 여부"),
|
|
28
|
+
multiple: z.boolean().optional().default(false).describe("다중 선택 가능 여부 (실제 컴포넌트에선 필수 prop — 단일 선택도 multiple={false} 명시)"),
|
|
28
29
|
useCheckboxOption: z.boolean().optional().default(false).describe("체크박스 옵션 사용 여부"),
|
|
29
30
|
useSelectAll: z.boolean().optional().default(false).describe("전체 선택 옵션 사용 여부"),
|
|
30
|
-
disableCloseOnSelect: z.boolean().optional().
|
|
31
|
+
disableCloseOnSelect: z.boolean().optional().describe("선택 시 닫힘 방지 여부 (기본값: multiple 값과 같음 — 다중 선택은 기본으로 열린 채 유지)"),
|
|
32
|
+
noOptionsText: z.string().optional().describe("옵션이 없을 때 표시 텍스트"),
|
|
33
|
+
inputValue: z.string().optional().describe("입력 텍스트 상태 변수명 (제어형 검색어) — onInputChange와 함께"),
|
|
34
|
+
onInputChange: z.string().optional().describe("입력 텍스트 변경 핸들러 함수명 ((e, value, reason) => void)"),
|
|
31
35
|
loading: z.boolean().optional().default(false).describe("로딩 상태 표시 여부"),
|
|
32
36
|
label: z.string().optional().describe("라벨 텍스트"),
|
|
33
37
|
placeholder: z.string().optional().describe("플레이스홀더 텍스트"),
|
|
@@ -42,7 +46,8 @@ export const AutocompleteSelectSchema = z.object({
|
|
|
42
46
|
groupBy: z.string().optional().describe("옵션 그룹핑 함수명 또는 인라인 화살표 함수. (option) => string 형태로 각 옵션이 속할 그룹 라벨을 반환 (예: (option) => option.group). 기본값 없음(그룹핑 안 함)"),
|
|
43
47
|
fitDropdownWidth: z.boolean().optional().describe("드롭다운 너비를 입력 필드 폭에 고정하고 긴 라벨은 줄바꿈 (boolean, 기본 false). false(기본)면 드롭다운이 옵션 라벨 폭에 맞게 확장되며, 화면 오른쪽 공간이 부족하면 잘리는 대신 왼쪽으로 이동. 좁은 레이아웃에서 드롭다운이 넓어지면 안 될 때 사용"),
|
|
44
48
|
dropdownMaxWidth: z.number().optional().describe("확장 모드(fitDropdownWidth=false)에서 드롭다운 최대 너비(px, number). 미지정(기본) 시 고정 상한 없이 뷰포트 폭까지 확장하고 그보다 긴 라벨만 줄바꿈 (예: 360)"),
|
|
45
|
-
onChange: z.string().optional().describe("선택 값 변경 콜백 함수명. (value, event?, reason?, details?) => void 형태이며 value는 multiple 여부에 따라 배열 또는 단일 아이템(null 가능). 기본값 없음(미지정 시 생성 코드에 onChange={setValue} 사용)")
|
|
49
|
+
onChange: z.string().optional().describe("선택 값 변경 콜백 함수명. (value, event?, reason?, details?) => void 형태이며 value는 multiple 여부에 따라 배열 또는 단일 아이템(null 가능). 기본값 없음(미지정 시 생성 코드에 onChange={setValue} 사용)"),
|
|
50
|
+
copilotId: z.string().optional().describe("Copilot 연동 ID — Copilot 매니페스트의 bind.copilotId와 매칭되어 AI가 이 컨트롤을 조작할 수 있게 함. useCommonComponents()로 받은 컴포넌트에서만 동작(로더 HOC가 소비 후 제거)"),
|
|
46
51
|
});
|
|
47
52
|
// Select 컴포넌트 함수 - 배열 반환
|
|
48
53
|
export function createSelectComponent() {
|
|
@@ -51,7 +56,7 @@ export function createSelectComponent() {
|
|
|
51
56
|
name: "createSelect",
|
|
52
57
|
description: `기본 셀렉트 컴포넌트 예제입니다.
|
|
53
58
|
|
|
54
|
-
- items: 옵션 배열
|
|
59
|
+
- items: 옵션 배열 [{ value, label }] (항목별 disabled는 지원하지 않음 — 필요하면 Autocomplete)
|
|
55
60
|
- multiple, placeholder, variant, size, error, disabled 등 다양한 props 지원
|
|
56
61
|
- value/onChange는 단일/다중 선택에 따라 배열 또는 단일 값
|
|
57
62
|
|
|
@@ -82,6 +87,8 @@ export function createSelectComponent() {
|
|
|
82
87
|
props.push(`multiple`);
|
|
83
88
|
if (args.placeholder)
|
|
84
89
|
props.push(`placeholder=\"${args.placeholder}\"`);
|
|
90
|
+
if (args.label)
|
|
91
|
+
props.push(`label=\"${args.label}\"`);
|
|
85
92
|
if (args.variant)
|
|
86
93
|
props.push(`variant=\"${args.variant}\"`);
|
|
87
94
|
if (args.size)
|
|
@@ -133,14 +140,20 @@ export function createSelectComponent() {
|
|
|
133
140
|
props.push(`items={${JSON.stringify(args.items)}}`);
|
|
134
141
|
if (args.value !== undefined)
|
|
135
142
|
props.push(`value={value}`);
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
// multiple은 d.ts상 필수 — 단일 선택도 명시
|
|
144
|
+
props.push(args.multiple ? `multiple` : `multiple={false}`);
|
|
138
145
|
if (args.useCheckboxOption)
|
|
139
146
|
props.push(`useCheckboxOption`);
|
|
140
147
|
if (args.useSelectAll)
|
|
141
148
|
props.push(`useSelectAll`);
|
|
142
|
-
if (args.disableCloseOnSelect)
|
|
143
|
-
props.push(`disableCloseOnSelect`);
|
|
149
|
+
if (args.disableCloseOnSelect !== undefined)
|
|
150
|
+
props.push(`disableCloseOnSelect={${args.disableCloseOnSelect}}`);
|
|
151
|
+
if (args.noOptionsText)
|
|
152
|
+
props.push(`noOptionsText=\"${args.noOptionsText}\"`);
|
|
153
|
+
if (args.inputValue)
|
|
154
|
+
props.push(`inputValue={${args.inputValue}}`);
|
|
155
|
+
if (args.onInputChange)
|
|
156
|
+
props.push(`onInputChange={${args.onInputChange}}`);
|
|
144
157
|
if (args.loading)
|
|
145
158
|
props.push(`loading`);
|
|
146
159
|
if (args.label)
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { jsxAttrs, jsxTag, jsxResult } from "./opsnow-common-jsx-helper.js";
|
|
2
3
|
// Stepper 컴포넌트 관련 스키마 정의 (예제 코드에 맞게 확장)
|
|
3
4
|
export const StepperSchema = z.object({
|
|
4
5
|
steps: z.array(z.object({
|
|
5
6
|
label: z.string().describe("스텝 라벨"),
|
|
6
|
-
status: z.
|
|
7
|
+
status: z.enum(["notStarted", "inProgress", "completed", "error", "warning", "info", "success"]).describe("스텝 상태 (실제 컴포넌트에선 필수, camelCase)"),
|
|
7
8
|
optionalText: z.string().optional().describe("옵셔널 텍스트"),
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
useCheckIcon: z.boolean().optional().describe("완료 스텝에 체크 아이콘 표시 (기본값: true)"),
|
|
10
|
+
completedStatus: z.boolean().optional().describe("완료 상태 강제 표시"),
|
|
10
11
|
// slot은 StepContent에서만 사용
|
|
11
12
|
})).describe("스텝 목록"),
|
|
12
13
|
activeStep: z.number().optional().default(0).describe("현재 스텝 인덱스"),
|
|
13
14
|
orientation: z.enum(["horizontal", "vertical"]).optional().default("horizontal").describe("스텝 방향"),
|
|
14
15
|
align: z.enum(["left", "center", "right"]).optional().describe("스텝 정렬"),
|
|
15
16
|
isSimpleView: z.boolean().optional().describe("심플 뷰 여부"),
|
|
16
|
-
|
|
17
|
+
isStepCompact: z.boolean().optional().describe("스텝 간격을 좁게 표시"),
|
|
17
18
|
onStepClick: z.string().optional().describe("스텝 클릭 핸들러 함수명"),
|
|
18
19
|
contentPadding: z.string().optional().describe("컨텐츠 패딩 스타일"),
|
|
19
20
|
contentHeight: z.string().optional().describe("컨텐츠 높이 스타일"),
|
|
@@ -21,6 +22,14 @@ export const StepperSchema = z.object({
|
|
|
21
22
|
contentDependency: z.boolean().optional().describe("컨텐츠 의존성 여부"),
|
|
22
23
|
setActiveStep: z.string().optional().describe("현재 스텝(activeStep) 상태를 변경하는 setter 함수명 (문자열, 예: 'setActiveStep'). (index: number) => void 시그니처로, 보통 useState의 setter 함수명을 그대로 전달. nonLinear 모드에서 스텝 클릭 이동 시 컴포넌트가 호출함. 스텝 클릭 동작은 nonLinear + onStepClick/setActiveStep으로만 제어됨")
|
|
23
24
|
});
|
|
25
|
+
export const StepButtonSchema = z.object({
|
|
26
|
+
prev: z.string().describe("이전 버튼 클릭 핸들러 함수명 (필수)"),
|
|
27
|
+
next: z.string().describe("다음 버튼 클릭 핸들러 함수명 (필수)"),
|
|
28
|
+
leftStepTitle: z.string().optional().describe("이전 버튼 텍스트 (기본값: 'left')"),
|
|
29
|
+
rightStepTitle: z.string().optional().describe("다음 버튼 텍스트 (기본값: 'right')"),
|
|
30
|
+
leftDisabled: z.boolean().optional().describe("이전 버튼 비활성화"),
|
|
31
|
+
rightDisabled: z.boolean().optional().describe("다음 버튼 비활성화"),
|
|
32
|
+
});
|
|
24
33
|
// Stepper 컴포넌트 함수 - 배열 반환
|
|
25
34
|
export function createStepperComponent() {
|
|
26
35
|
return [
|
|
@@ -35,7 +44,7 @@ export function createStepperComponent() {
|
|
|
35
44
|
\`\`\``,
|
|
36
45
|
parameters: StepperSchema,
|
|
37
46
|
handler: async (args) => {
|
|
38
|
-
const { steps, activeStep = 0, orientation = "horizontal", align, isSimpleView,
|
|
47
|
+
const { steps, activeStep = 0, orientation = "horizontal", align, isSimpleView, isStepCompact, onStepClick, contentPadding, contentHeight, nonLinear, contentDependency } = args;
|
|
39
48
|
// 태그 props만 생성
|
|
40
49
|
const propList = [
|
|
41
50
|
`steps={steps}`,
|
|
@@ -43,7 +52,7 @@ export function createStepperComponent() {
|
|
|
43
52
|
`orientation=\"${orientation}\"`,
|
|
44
53
|
align ? `align=\"${align}\"` : '',
|
|
45
54
|
isSimpleView ? 'isSimpleView' : '',
|
|
46
|
-
|
|
55
|
+
isStepCompact ? 'isStepCompact' : '',
|
|
47
56
|
onStepClick ? `onStepClick={${onStepClick}}` : '',
|
|
48
57
|
contentPadding ? `contentPadding=\"${contentPadding}\"` : '',
|
|
49
58
|
contentHeight ? `contentHeight=\"${contentHeight}\"` : '',
|
|
@@ -64,6 +73,20 @@ export function createStepperComponent() {
|
|
|
64
73
|
]
|
|
65
74
|
};
|
|
66
75
|
}
|
|
67
|
-
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "createStepButton",
|
|
79
|
+
description: `StepButton 컴포넌트 - Stepper(위자드) 하단의 이전/다음 버튼 쌍
|
|
80
|
+
leftStepTitle/rightStepTitle 기본값이 'left'/'right'라 실제 화면에서는 반드시 텍스트를 지정하세요.
|
|
81
|
+
⚠️ 로더 2.0.21의 TypeScript 타입(useCommonComponents 반환 타입)에는 OpsnowCommonStepButton이 빠져 있습니다 — 런타임에는 있으므로 .tsx에서는 타입 단언이 필요할 수 있습니다.
|
|
82
|
+
|
|
83
|
+
**import:**
|
|
84
|
+
\`\`\`javascript
|
|
85
|
+
import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader';
|
|
86
|
+
const { OpsnowCommonStepButton } = useCommonComponents();
|
|
87
|
+
\`\`\``,
|
|
88
|
+
parameters: StepButtonSchema,
|
|
89
|
+
handler: async (args) => jsxResult(jsxTag("OpsnowCommonStepButton", jsxAttrs(args, { exprKeys: ["prev", "next"] }))),
|
|
90
|
+
},
|
|
68
91
|
];
|
|
69
92
|
}
|
|
@@ -4,7 +4,7 @@ export const TabSchema = z.object({
|
|
|
4
4
|
items: z
|
|
5
5
|
.array(z.object({
|
|
6
6
|
label: z.string().describe("탭 라벨 - icon이 들어가지 않음 icon 사용 시 반드시 iconName으로 사용"),
|
|
7
|
-
content: z.string().describe("각 탭에 들어가는 내용"),
|
|
7
|
+
content: z.string().optional().describe("각 탭에 들어가는 내용 (탭 아래 패널, 선택)"),
|
|
8
8
|
disabled: z
|
|
9
9
|
.boolean()
|
|
10
10
|
.optional()
|
|
@@ -24,10 +24,12 @@ export const TabSchema = z.object({
|
|
|
24
24
|
fullWidth: z.boolean().optional().describe("탭 전체 너비 사용 여부"),
|
|
25
25
|
value: z
|
|
26
26
|
.string()
|
|
27
|
-
.describe("
|
|
27
|
+
.describe("선택된 탭 인덱스 상태 변수명 (필수) — 값은 숫자 인덱스(useState(0)). 패널은 이 인덱스로 매칭"),
|
|
28
28
|
depth: z.number().min(1).max(3).optional().describe("탭 깊이 1~3"),
|
|
29
|
-
onChange: z.string().
|
|
29
|
+
onChange: z.string().describe("탭 변경 핸들러 함수명 (필수) — (e, newIndex) => setValue(newIndex)"),
|
|
30
30
|
color: z.enum(["primary", "secondary"]).optional().describe("탭 색상"),
|
|
31
|
+
copilotId: z.string().optional().describe("Copilot 연동 ID — Copilot 매니페스트의 bind.copilotId와 매칭되어 AI가 이 컨트롤을 조작할 수 있게 함. useCommonComponents()로 받은 컴포넌트에서만 동작(로더 HOC가 소비 후 제거)"),
|
|
32
|
+
copilotTabIds: z.array(z.union([z.string(), z.number()])).optional().describe("Copilot 연동용 탭 의미 ID 목록 — items 순서(value 인덱스)와 1:1 매핑. copilotId와 함께 사용"),
|
|
31
33
|
}).describe("탭 컴포넌트 - createIconsComponent에서 iconName을 반드시 참조하여 string으로 입력");
|
|
32
34
|
// Tab 컴포넌트 함수 - 배열 반환
|
|
33
35
|
export function createTabComponent() {
|
|
@@ -70,6 +70,7 @@ export function createToastPopupComponent() {
|
|
|
70
70
|
description: `토스트 팝업 컴포넌트 - 버튼 클릭 시 간단한 알림 메시지 표시
|
|
71
71
|
토스트 팝업 사용 시 버튼 컴포넌트의 onClick은 반드시 필요함.
|
|
72
72
|
버튼 컴포넌트 onClick 함수 내부에 showToast를 사용하여 토스트 팝업 표시
|
|
73
|
+
⚠️ ToastProvider는 GlobalProvider에 이미 내장(동시 최대 5개) — Provider를 추가로 감싸지 말 것 (중복 시 토스트가 이중으로 쌓임)
|
|
73
74
|
|
|
74
75
|
**import**:
|
|
75
76
|
import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader';
|
|
@@ -38,7 +38,7 @@ export const TooltipSchema = z.object({
|
|
|
38
38
|
.describe("아이콘 이름 - iconProps.useIcon이 true일 경우 필수"),
|
|
39
39
|
useIcon: z.boolean().optional().describe("아이콘 사용 여부 - iconName이 있을 경우 iconProps.useIcon은 true여야 함, useMuiIcon 과 동시에 true안됨"),
|
|
40
40
|
useMuiIcon: z.boolean().optional().describe("MUI 아이콘 사용 여부 - useIcon 과 동시에 true 안됨"),
|
|
41
|
-
label: z.string().describe("툴팁
|
|
41
|
+
label: z.string().optional().describe("useMuiIcon일 때 표시할 MUI(Material) 아이콘 이름 (예: 'info'). 툴팁 문구가 아님 — 문구는 titleProps.title. 미지정 시 add_icon"),
|
|
42
42
|
colorProps: z
|
|
43
43
|
.object({
|
|
44
44
|
commonColor: z.string().optional().describe("툴팁 색상"),
|
|
@@ -50,6 +50,7 @@ export const TooltipSchema = z.object({
|
|
|
50
50
|
"info",
|
|
51
51
|
"success",
|
|
52
52
|
"warning",
|
|
53
|
+
"inherit",
|
|
53
54
|
])
|
|
54
55
|
.optional()
|
|
55
56
|
.describe("툴팁 MUI 색상"),
|
|
@@ -60,27 +61,18 @@ export const TooltipSchema = z.object({
|
|
|
60
61
|
})
|
|
61
62
|
.optional()
|
|
62
63
|
.describe("isIconTooltip이 true일 경우 추가 필드"),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
disableTouchListener: z.boolean().describe("터치 리스너 비활성화 여부"),
|
|
68
|
-
disableInteractive: z.boolean().describe("대화형 컴포넌트 비활성화 여부"),
|
|
64
|
+
disableFocusListener: z.boolean().optional().describe("포커스 리스너 비활성화 여부"),
|
|
65
|
+
disableHoverListener: z.boolean().optional().describe("호버 리스너 비활성화 여부"),
|
|
66
|
+
disableTouchListener: z.boolean().optional().describe("터치 리스너 비활성화 여부"),
|
|
67
|
+
disableInteractive: z.boolean().optional().describe("대화형 컴포넌트 비활성화 여부"),
|
|
69
68
|
enterDelay: z.number().optional().describe("툴팁 진입 지연 시간 (ms)"),
|
|
70
|
-
enterTouchDelay: z
|
|
71
|
-
|
|
72
|
-
.optional()
|
|
73
|
-
.describe("툴팁 진입 터치 지연 시간 (ms)"),
|
|
74
|
-
enterNextDelay: z
|
|
75
|
-
.number()
|
|
76
|
-
.optional()
|
|
77
|
-
.describe("툴팁 진입 다음 지연 시간 (ms)"),
|
|
69
|
+
enterTouchDelay: z.number().optional().describe("툴팁 진입 터치 지연 시간 (ms)"),
|
|
70
|
+
enterNextDelay: z.number().optional().describe("툴팁 진입 다음 지연 시간 (ms)"),
|
|
78
71
|
leaveDelay: z.number().optional().describe("툴팁 이탈 지연 시간 (ms)"),
|
|
79
|
-
leaveNextDelay: z
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
open: z.boolean().describe("툴팁 열림 여부"),
|
|
72
|
+
leaveNextDelay: z.number().optional().describe("툴팁 이탈 다음 지연 시간 (ms)"),
|
|
73
|
+
open: z.boolean().optional().describe("툴팁 열림 여부 (IconTooltip에서는 무시됨)"),
|
|
74
|
+
onOpen: z.string().optional().describe("툴팁 열림 시 실행할 함수명 (IconTooltip에서는 무시됨)"),
|
|
75
|
+
onClose: z.string().optional().describe("툴팁 닫힘 시 실행할 함수명 (IconTooltip에서는 무시됨)"),
|
|
84
76
|
tooltipFullWidth: z
|
|
85
77
|
.boolean()
|
|
86
78
|
.optional()
|
|
@@ -107,7 +99,8 @@ export function createTooltipComponent() {
|
|
|
107
99
|
handler: async (args) => {
|
|
108
100
|
let code = "";
|
|
109
101
|
const props = [];
|
|
110
|
-
|
|
102
|
+
// ref(openTooltip/closeTooltip)는 OpsnowCommonTooltip 전용
|
|
103
|
+
if (args.ref && !args.isIconTooltip) {
|
|
111
104
|
code += `const ${args.ref} = useRef(null);
|
|
112
105
|
// ref 객체에는 openTooltip(), closeTooltip(), getOpenState() 메서드가 제공됨`;
|
|
113
106
|
props.push(`ref={${args.ref}}`);
|
|
@@ -116,14 +109,16 @@ export function createTooltipComponent() {
|
|
|
116
109
|
if (args.titleProps.title)
|
|
117
110
|
props.push(`title="${args.titleProps.title}"`);
|
|
118
111
|
else if (args.titleProps.imgSrc) {
|
|
119
|
-
props.push(`title = {<img src="${args.titleProps.imgSrc}" ${args.titleProps.imgAlt ?
|
|
112
|
+
props.push(`title = {<img src="${args.titleProps.imgSrc}" ${args.titleProps.imgAlt ? `alt="${args.titleProps.imgAlt}"` : ""} />}`);
|
|
120
113
|
}
|
|
121
114
|
}
|
|
115
|
+
if (args.placement)
|
|
116
|
+
props.push(`placement="${args.placement}"`);
|
|
122
117
|
if (args.iconTooltipProps) {
|
|
123
118
|
if (args.iconTooltipProps.iconName)
|
|
124
119
|
props.push(`iconName={"${args.iconTooltipProps.iconName}"}`);
|
|
125
|
-
if (args.
|
|
126
|
-
props.push(`
|
|
120
|
+
if (args.iconTooltipProps.label)
|
|
121
|
+
props.push(`label="${args.iconTooltipProps.label}"`);
|
|
127
122
|
if (args.iconTooltipProps.useIcon)
|
|
128
123
|
props.push(`useIcon={${args.iconTooltipProps.useIcon}}`);
|
|
129
124
|
if (args.iconTooltipProps.useMuiIcon)
|
|
@@ -137,26 +132,33 @@ export function createTooltipComponent() {
|
|
|
137
132
|
if (args.iconTooltipProps.size)
|
|
138
133
|
props.push(`size={${args.iconTooltipProps.size}}`);
|
|
139
134
|
}
|
|
140
|
-
if (args.disableFocusListener)
|
|
141
|
-
props.push(`disableFocusListener`);
|
|
142
|
-
if (args.disableHoverListener)
|
|
143
|
-
props.push(`disableHoverListener`);
|
|
144
|
-
if (args.disableTouchListener)
|
|
145
|
-
props.push(`disableTouchListener`);
|
|
146
135
|
if (args.disableInteractive)
|
|
147
136
|
props.push(`disableInteractive`);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
137
|
+
// 리스너·딜레이·open 제어는 IconTooltip이 받지 않음
|
|
138
|
+
if (!args.isIconTooltip) {
|
|
139
|
+
if (args.disableFocusListener)
|
|
140
|
+
props.push(`disableFocusListener`);
|
|
141
|
+
if (args.disableHoverListener)
|
|
142
|
+
props.push(`disableHoverListener`);
|
|
143
|
+
if (args.disableTouchListener)
|
|
144
|
+
props.push(`disableTouchListener`);
|
|
145
|
+
if (args.enterDelay)
|
|
146
|
+
props.push(`enterDelay={${args.enterDelay}}`);
|
|
147
|
+
if (args.enterTouchDelay)
|
|
148
|
+
props.push(`enterTouchDelay={${args.enterTouchDelay}}`);
|
|
149
|
+
if (args.enterNextDelay)
|
|
150
|
+
props.push(`enterNextDelay={${args.enterNextDelay}}`);
|
|
151
|
+
if (args.leaveDelay)
|
|
152
|
+
props.push(`leaveDelay={${args.leaveDelay}}`);
|
|
153
|
+
if (args.leaveNextDelay)
|
|
154
|
+
props.push(`leaveNextDelay={${args.leaveNextDelay}}`);
|
|
155
|
+
if (args.open !== undefined)
|
|
156
|
+
props.push(`open={${args.open}}`);
|
|
157
|
+
if (args.onOpen)
|
|
158
|
+
props.push(`onOpen={${args.onOpen}}`);
|
|
159
|
+
if (args.onClose)
|
|
160
|
+
props.push(`onClose={${args.onClose}}`);
|
|
161
|
+
}
|
|
160
162
|
if (args.tooltipFullWidth)
|
|
161
163
|
props.push(`tooltipFullWidth={${args.tooltipFullWidth}}`);
|
|
162
164
|
if (args.tooltipPreview) {
|
|
@@ -165,10 +167,6 @@ export function createTooltipComponent() {
|
|
|
165
167
|
else
|
|
166
168
|
props.push(`useTooltipPreview={${args.tooltipPreview}}`);
|
|
167
169
|
}
|
|
168
|
-
if (args.onOpen)
|
|
169
|
-
props.push(`onOpen={${args.onOpen}}`);
|
|
170
|
-
if (args.onClose)
|
|
171
|
-
props.push(`onClose={${args.onClose}}`);
|
|
172
170
|
if (args.isIconTooltip) {
|
|
173
171
|
code += `
|
|
174
172
|
<OpsnowCommonIconTooltip ${props.join(" ")}>
|
|
@@ -16,20 +16,25 @@ const variantList = [
|
|
|
16
16
|
// z.enum에 [string, ...string[]] 타입으로 변환
|
|
17
17
|
const variantListForEnum = variantList;
|
|
18
18
|
// 1. CommonPalette 색상 그룹과 단계 정의
|
|
19
|
+
// style 2.x 런타임 팔레트 기준 (pink 없음, gray만 0 단계 있음)
|
|
19
20
|
const commonPaletteColors = [
|
|
20
|
-
'gray', 'darkblue', 'blue', 'skyblue', 'green', 'cyan', 'yellow', '
|
|
21
|
-
// 필요시 etc. 추가
|
|
21
|
+
'gray', 'darkblue', 'blue', 'skyblue', 'green', 'cyan', 'yellow', 'purple', 'orange', 'red',
|
|
22
22
|
];
|
|
23
23
|
const commonPaletteDepths = [
|
|
24
|
-
'100', '200', '300', '400', '500', '600', '700', '800', '900',
|
|
24
|
+
'50', '100', '200', '300', '400', '500', '600', '700', '800', '900',
|
|
25
25
|
];
|
|
26
|
+
const commonPaletteEtc = ['white', 'surface', 'shadow1', 'shadow2'];
|
|
26
27
|
// 2. 모든 조합을 string literal union 타입으로 생성
|
|
27
|
-
const commonPaletteList =
|
|
28
|
+
const commonPaletteList = [
|
|
29
|
+
'commonPalette.gray.0',
|
|
30
|
+
...commonPaletteColors.flatMap(color => commonPaletteDepths.map(depth => `commonPalette.${color}.${depth}`)),
|
|
31
|
+
...commonPaletteEtc.map(key => `commonPalette.etc.${key}`),
|
|
32
|
+
];
|
|
28
33
|
const commonPaletteListForEnum = commonPaletteList;
|
|
29
34
|
export const TypographySchema = z.object({
|
|
30
35
|
text: z.string().describe("표시할 텍스트"),
|
|
31
36
|
variant: z.enum(variantListForEnum).describe("타이포그래피 스타일(variant, e-r1~e-b13만 허용)"),
|
|
32
|
-
color: z.enum(commonPaletteListForEnum).optional().describe("
|
|
37
|
+
color: z.enum(commonPaletteListForEnum).optional().describe("CommonPalette 팔레트 경로 (예: commonPalette.green.300, commonPalette.gray.0, commonPalette.etc.white)"),
|
|
33
38
|
theme: z.enum([
|
|
34
39
|
"primary", "secondary", "warning", "success", "error", "info", "description", "disabled"
|
|
35
40
|
]).optional().describe("테마 색상"),
|
|
@@ -53,6 +58,7 @@ export function createTypographyComponent() {
|
|
|
53
58
|
|
|
54
59
|
- variant: e-r1~e-b13만 허용
|
|
55
60
|
- 예제 테이블 스타일에 맞는 Typography만 생성 가능
|
|
61
|
+
- sx·className은 적용되지 않음 (내부에서 덮어씀) — 여백 등은 바깥 <Box sx={{ ... }}>로 감싸서 적용. 색·굵기·크기는 color·fontWeight·fontSize prop 사용
|
|
56
62
|
|
|
57
63
|
\`\`\`javascript
|
|
58
64
|
import { OpsnowCommonTypography } from '@opsnow-common/opsnow-common-style'
|
|
Binary file
|
package/build/index.js
CHANGED
|
@@ -112,10 +112,12 @@ Just like color tokens (theme.palette.commonPalette), all layout spacing uses th
|
|
|
112
112
|
cardGap 16px - gap between elements inside a card
|
|
113
113
|
cardPadding '16px 20px' - padding of a filter bar / card container
|
|
114
114
|
pagePadding 24px - page content padding
|
|
115
|
+
minTouchTarget 44px - minimum size of touch targets (buttons/icons on mobile)
|
|
115
116
|
|
|
116
117
|
Use theme in sx/styled: sx={theme => ({ gap: theme.commonSpacing.filterGap })} or sx={{ gap: theme => theme.commonSpacing.filterLabelGap }}.
|
|
117
118
|
Pure CSS (no theme context): var(--opsnow-spacing-filter-gap), --opsnow-spacing-filter-label-gap, --opsnow-spacing-section-gap, --opsnow-spacing-card-gap, --opsnow-spacing-card-padding, --opsnow-spacing-page-padding, --opsnow-spacing-filter-row-gap.
|
|
118
119
|
Outside theme context (constants/utils): import { commonSpacing } from '@opsnow-common/opsnow-common-style'; commonSpacing.filterGap // '24px'.
|
|
120
|
+
Responsive (@opsnow-common/opsnow-common-style): useOpsnowBreakpoint() → { isMobile(<900), isTablet(900~1199), isDesktop(≥1200), isTabletUp, device } only when the render tree differs; for style-only changes use theme.breakpoints.down('md') or the media-query strings mobileOnly / tabletUp / desktopUp inside sx/styled (no re-render). Constants: OPSNOW_BREAKPOINT_VALUES, OPSNOW_MOBILE_MAX_WIDTH (767.95 — current header/grid mobile boundary), OPSNOW_DESKTOP_MIN_WIDTH (1200), OPSNOW_MIN_TOUCH_TARGET (44).
|
|
119
121
|
Found hardcoded px spacing? You MUST replace it: (1) use the token for that purpose → (2) if none fits, use theme.spacing(n) for generic multiples (base 4px → theme.spacing(2) = 8px) → (3) still nothing? DO NOT keep px — ask to add a new token in the style package (one row).
|
|
120
122
|
|
|
121
123
|
--- Filter layout (Select/Autocomplete/DatePicker/DataGrid search area) ---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opsnow-mcp/opsnow-mcp-common-ui-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
|
14
14
|
"build:skill": "npx tsx scripts/build-skill.ts",
|
|
15
|
+
"sync:icons": "npx tsx scripts/sync-icon-names.ts",
|
|
15
16
|
"build:skill:clean": "rm -rf skills/plugins/opsnow-common-ui-skill/skills && npm run build:skill",
|
|
16
17
|
"build:all": "npm run build && npm run build:skill",
|
|
17
18
|
"start": "node --loader ts-node/esm src/index.ts",
|