@reopt-ai/opt-ui 1.5.0 → 1.7.0
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/COMPONENT_CATALOG.md +178 -50
- package/README.md +28 -7
- package/dist/app.css +170 -0
- package/dist/core/index.cjs +164 -324
- package/dist/core/index.d.cts +3 -6
- package/dist/core/index.d.ts +3 -6
- package/dist/core/index.js +3 -323
- package/dist/docs/01-getting-started.md +25 -5
- package/dist/docs/02-components/01-core.md +36 -28
- package/dist/docs/02-components/02-visuals.md +1 -1
- package/dist/docs/02-components/03-shells.md +144 -23
- package/dist/docs/02-components/04-surfaces.md +1 -1
- package/dist/docs/02-components/index.md +4 -4
- package/dist/docs/03-recipes/03-layouts.md +16 -12
- package/dist/docs/05-migration/01-breaking-changes.md +46 -1
- package/dist/field-sidebar-BTZCBviA.d.cts +1031 -0
- package/dist/field-sidebar-BTZCBviA.d.cts.map +1 -0
- package/dist/field-sidebar-CB8vjvUM.d.ts +1031 -0
- package/dist/field-sidebar-CB8vjvUM.d.ts.map +1 -0
- package/dist/field-sidebar-Cs-J-5VE.js +4233 -0
- package/dist/field-sidebar-Cs-J-5VE.js.map +1 -0
- package/dist/field-sidebar-CzIQX70-.cjs +4561 -0
- package/dist/id-registry.cjs +1939 -1872
- package/dist/id-registry.d.cts +14 -11
- package/dist/id-registry.d.cts.map +1 -0
- package/dist/id-registry.d.ts +14 -11
- package/dist/id-registry.d.ts.map +1 -0
- package/dist/id-registry.js +1937 -1871
- package/dist/id-registry.js.map +1 -0
- package/dist/id-registry.json +113 -28
- package/dist/index.cjs +8380 -9790
- package/dist/index.d.cts +1555 -1442
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +1555 -1442
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7996 -9778
- package/dist/index.js.map +1 -0
- package/dist/meta.cjs +7753 -6875
- package/dist/meta.d.cts.map +1 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +7752 -6846
- package/dist/meta.js.map +1 -0
- package/dist/pagination-DWbvACuN.js +3850 -0
- package/dist/pagination-DWbvACuN.js.map +1 -0
- package/dist/pagination-DjfxBcjX.cjs +4739 -0
- package/dist/query.cjs +386 -0
- package/dist/query.d.cts +141 -0
- package/dist/query.d.cts.map +1 -0
- package/dist/query.d.ts +141 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +371 -0
- package/dist/query.js.map +1 -0
- package/dist/shader-surface-BUPZ0P-n.js +3654 -0
- package/dist/shader-surface-BUPZ0P-n.js.map +1 -0
- package/dist/shader-surface-BfTP9c1Q.d.ts +1788 -0
- package/dist/shader-surface-BfTP9c1Q.d.ts.map +1 -0
- package/dist/shader-surface-DRrcLrWf.d.cts +1788 -0
- package/dist/shader-surface-DRrcLrWf.d.cts.map +1 -0
- package/dist/shader-surface-Fav5K9UC.cjs +4041 -0
- package/dist/shells/index.cjs +58 -65
- package/dist/shells/index.d.cts +4 -5
- package/dist/shells/index.d.ts +4 -5
- package/dist/shells/index.js +4 -64
- package/dist/tailwind.css +49 -0
- package/dist/theme/presets/default.css +2 -2
- package/dist/theme/presets/minimal.css +2 -2
- package/dist/theme/presets/mono-dark.css +2 -2
- package/dist/theme/presets/natural.css +1 -1
- package/dist/theme/presets/pro.css +2 -2
- package/dist/theme/server.cjs +257 -228
- package/dist/theme/server.d.cts +48 -60
- package/dist/theme/server.d.cts.map +1 -0
- package/dist/theme/server.d.ts +48 -60
- package/dist/theme/server.d.ts.map +1 -0
- package/dist/theme/server.js +234 -189
- package/dist/theme/server.js.map +1 -0
- package/dist/types-D0FlcYnM.d.cts +301 -0
- package/dist/types-D0FlcYnM.d.cts.map +1 -0
- package/dist/types-D0FlcYnM.d.ts +301 -0
- package/dist/types-D0FlcYnM.d.ts.map +1 -0
- package/dist/visuals/index.cjs +10 -4
- package/dist/visuals/index.d.cts +2 -1
- package/dist/visuals/index.d.ts +2 -1
- package/dist/visuals/index.js +1 -2
- package/package.json +27 -11
- package/dist/chunk-3GWWZKX7.js +0 -38
- package/dist/chunk-3QFYBBL6.cjs +0 -4759
- package/dist/chunk-3XD4HIFL.js +0 -3241
- package/dist/chunk-AFF2HPE5.cjs +0 -5008
- package/dist/chunk-NXZJIHEZ.cjs +0 -3241
- package/dist/chunk-ONE3C5RV.cjs +0 -38
- package/dist/chunk-RBM2RNC2.js +0 -5008
- package/dist/chunk-VBGPEW45.js +0 -4759
- package/dist/index-BZ_lBlO1.d.ts +0 -474
- package/dist/index-BuvxoWHf.d.cts +0 -474
- package/dist/index-DWyqDIkH.d.cts +0 -1689
- package/dist/index-Uyijm14M.d.ts +0 -1689
- package/dist/types-D4-0lwaE.d.cts +0 -298
- package/dist/types-D4-0lwaE.d.ts +0 -298
package/COMPONENT_CATALOG.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- DEPRECATED: Prefer dist/docs/02-components/ for per-layer reference. -->
|
|
4
4
|
<!-- Auto-generated from ComponentMeta. Do not edit. -->
|
|
5
|
-
<!-- Version: 1.
|
|
5
|
+
<!-- Version: 1.6.0 -->
|
|
6
6
|
|
|
7
7
|
## Quick Stats
|
|
8
8
|
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
| --------- | ------- |
|
|
11
11
|
| Core | 59 |
|
|
12
12
|
| Visuals | 0 |
|
|
13
|
-
| Shells |
|
|
13
|
+
| Shells | 80 |
|
|
14
14
|
| Surfaces | 0 |
|
|
15
|
-
| **Total** | **
|
|
15
|
+
| **Total** | **139** |
|
|
16
16
|
|
|
17
17
|
## Component Selection Guide
|
|
18
18
|
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
| Toggle | 눌림(pressed) 두 상태 버튼. 단독 사용하거나 ToggleGroup으로 묶어 단일/다중 선택을 만든다. | `Toggle`, `ToggleGroup` |
|
|
185
185
|
| Accordion | 수직으로 쌓인 펼침/접힘 패널. single(한 개)/multiple(여러 개) 모드와 collapsible 지원. | `AccordionRoot`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` |
|
|
186
186
|
| Meter | 범위 내 스칼라 측정값 게이지 (디스크 사용량·점수·용량 등). role=meter로 작업 진행률(Progress)과 구분된다. | `Meter` |
|
|
187
|
-
| BlockLayout | Block 루트 레이아웃.
|
|
187
|
+
| BlockLayout | Block 루트 레이아웃. 자식 간 section spacing과 선택적 시맨틱 inset을 제공하고 loading prop으로 LoadingOverlay를 자동 래핑합니다. | `BlockLayout` |
|
|
188
188
|
| createBlock | Block 팩토리 함수. BlockLayout 래핑을 구조적으로 강제하여 loading/className 처리를 자동화합니다. | `createBlock` |
|
|
189
189
|
| StarRating | 1~N점 별점을 선택하는 인터랙티브 레이팅 입력. 읽기 전용 표시도 지원. | `StarRating` |
|
|
190
190
|
| ErrorBoundary | React 에러 바운더리. 자식 컴포넌트 렌더 에러를 잡아 fallback UI를 표시합니다. | `ErrorBoundary` |
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
| Component | Description | Key Exports |
|
|
197
197
|
| --------- | ----------- | ----------- |
|
|
198
198
|
|
|
199
|
-
## Shell Components (
|
|
199
|
+
## Shell Components (80)
|
|
200
200
|
|
|
201
201
|
### Navigation & Layout
|
|
202
202
|
|
|
@@ -328,15 +328,20 @@
|
|
|
328
328
|
|
|
329
329
|
### Other
|
|
330
330
|
|
|
331
|
-
| Component
|
|
332
|
-
|
|
|
333
|
-
| PageAside
|
|
334
|
-
| FailureList
|
|
335
|
-
| KeyValueEditor
|
|
336
|
-
| AuditTimeline
|
|
337
|
-
| ChatSidebar
|
|
338
|
-
| ChatInput
|
|
339
|
-
| ChatMessageList
|
|
331
|
+
| Component | Description | Key Exports |
|
|
332
|
+
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
|
333
|
+
| PageAside | Sticky 페이지 사이드 aside chrome. 고정 너비 + header/body/footer 3-slot. | `PageAside` |
|
|
334
|
+
| FailureList | 실패 목록 패널. severity별 색상 강조, 그룹핑, 액션 슬롯을 지원합니다. | `FailureList` |
|
|
335
|
+
| KeyValueEditor | 키-값 쌍 편집기. 동적 행 추가/삭제, 비밀값 토글, 유효성 검사를 지원합니다. | `KeyValueEditor` |
|
|
336
|
+
| AuditTimeline | 변경 이력 타임라인. 액션별 색상 코딩 + 확장 가능한 diff 뷰. | `AuditTimeline` |
|
|
337
|
+
| ChatSidebar | AI 채팅 사이드바. 대화 목록, 검색, 새 대화 버튼. | `ChatSidebar` |
|
|
338
|
+
| ChatInput | 채팅 입력 컴포넌트. 자동 리사이즈 textarea, 파일 첨부, 모델/스타일 Select. | `ChatInput` |
|
|
339
|
+
| ChatMessageList | 채팅 메시지 목록. 역할별 말풍선, 타이핑 인디케이터, 자동 스크롤. | `ChatMessageList` |
|
|
340
|
+
| TimeRangeControl | date math(now-7d, now/d) 기반 시간 범위 컨트롤. quick select, 프리셋/최근 사용, 명시적 Update, 자동 갱신, 창 이동·확대/축소 버튼을 제공합니다. | `TimeRangeControl`, `DEFAULT_TIME_PRESETS` |
|
|
341
|
+
| TimeSeriesPanel | 시간 범위 컨트롤과 시계열 차트를 한 단위로 묶은 패널. 드래그 줌과 줌 히스토리(되돌리기), 범례 토글을 포함합니다. | `TimeSeriesPanel` |
|
|
342
|
+
| LogTable | 계속 도착하는 로그용 윈도잉 테이블. 컬럼 정의 기반, 상단 삽입 시 스크롤 위치 보존, follow 상태 보고, 셀 값 즉시 필터, 밀도·정렬을 지원합니다. | `LogTable` |
|
|
343
|
+
| QueryBar | 검색과 필터를 한 입력으로 합친 쿼리 바. field:value, -부정, (a or b), 비교 연산, 필드·값 자동완성, 절(clause) 칩을 지원합니다. | `QueryBar` |
|
|
344
|
+
| FieldSidebar | 데이터에 어떤 필드가 있고 각 필드가 무슨 값을 갖는지 보여주는 사이드바. 값 분포 막대, 컬럼으로 승격, 값 기준 포함/제외 필터를 제공합니다. | `FieldSidebar` |
|
|
340
345
|
|
|
341
346
|
## Surface Components (0)
|
|
342
347
|
|
|
@@ -373,9 +378,11 @@
|
|
|
373
378
|
|
|
374
379
|
**Import:** `import { Kbd } from "@reopt-ai/opt-ui"`
|
|
375
380
|
|
|
376
|
-
| Prop
|
|
377
|
-
|
|
|
378
|
-
| `children`
|
|
381
|
+
| Prop | Type | Required | Default | Description |
|
|
382
|
+
| ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------- |
|
|
383
|
+
| `children` | `ReactNode` | Yes | | 표시할 단축키 텍스트 |
|
|
384
|
+
| `hint` | `boolean` | | | 인라인 힌트 배지로 표시. `data-shortcut-hints="hidden"`일 때 숨겨진다 (app.css) |
|
|
385
|
+
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
379
386
|
|
|
380
387
|
#### Separator
|
|
381
388
|
|
|
@@ -542,26 +549,31 @@
|
|
|
542
549
|
|
|
543
550
|
**TabsRoot:**
|
|
544
551
|
|
|
545
|
-
| Prop | Type | Required | Default | Description
|
|
546
|
-
| ------------------- | ------------------------------ | -------- | ------- |
|
|
547
|
-
| `
|
|
548
|
-
| `
|
|
549
|
-
| `
|
|
552
|
+
| Prop | Type | Required | Default | Description |
|
|
553
|
+
| ------------------- | ------------------------------ | -------- | ------- | -------------------------------------------------------------------------------------- |
|
|
554
|
+
| `variant` | `"underline" \| "workspace"` | | | 탭 프레임 형태. workspace는 편집기 탭(문서/쿼리처럼 열고 닫히며 상태를 갖는 작업 단위) |
|
|
555
|
+
| `defaultSelectedId` | `string` | | | 초기 선택된 탭 ID |
|
|
556
|
+
| `selectedId` | `string \| null` | | | 제어 모드: 선택된 탭 ID |
|
|
557
|
+
| `setSelectedId` | `(id: string \| null) => void` | | | 제어 모드: 탭 변경 핸들러 |
|
|
550
558
|
|
|
551
559
|
**TabList:**
|
|
552
560
|
|
|
553
|
-
| Prop | Type | Required | Default | Description
|
|
554
|
-
| ----------- | ----------- | -------- | ------- |
|
|
555
|
-
| `children` | `ReactNode` | Yes | | Tab 요소들
|
|
556
|
-
| `
|
|
561
|
+
| Prop | Type | Required | Default | Description |
|
|
562
|
+
| ----------- | ----------- | -------- | ------- | -------------------------------------------------------------------------------------- |
|
|
563
|
+
| `children` | `ReactNode` | Yes | | Tab 요소들 |
|
|
564
|
+
| `actions` | `ReactNode` | | | 탭 줄 오른쪽 액션 영역 (새 탭, 닫기 등). tablist 바깥에 렌더돼 탭 순회에 끼어들지 않음 |
|
|
565
|
+
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
557
566
|
|
|
558
567
|
**Tab:**
|
|
559
568
|
|
|
560
|
-
| Prop
|
|
561
|
-
|
|
|
562
|
-
| `id`
|
|
563
|
-
| `children`
|
|
564
|
-
| `
|
|
569
|
+
| Prop | Type | Required | Default | Description |
|
|
570
|
+
| ------------- | ---------------------- | -------- | ------- | ------------------------------------------------- |
|
|
571
|
+
| `id` | `string` | Yes | | 탭 고유 ID (TabPanel의 tabId와 매칭) |
|
|
572
|
+
| `children` | `ReactNode` | Yes | | 탭 레이블 |
|
|
573
|
+
| `icon` | `ReactNode` | | | 탭 이름 앞 아이콘. 활성 탭에서 accent 색으로 전환 |
|
|
574
|
+
| `status` | `"dirty" \| "running"` | | | 저장되지 않은 변경 / 실행 중 인디케이터 |
|
|
575
|
+
| `statusLabel` | `string` | | | status 인디케이터의 접근성 레이블 |
|
|
576
|
+
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
565
577
|
|
|
566
578
|
**TabPanel:**
|
|
567
579
|
|
|
@@ -1877,13 +1889,14 @@ import {
|
|
|
1877
1889
|
|
|
1878
1890
|
**Import:** `import { BlockLayout } from "@reopt-ai/opt-ui"`
|
|
1879
1891
|
|
|
1880
|
-
| Prop | Type | Required | Default | Description
|
|
1881
|
-
| -------------- | --------------------------------------------- | -------- | --------- |
|
|
1882
|
-
| `children` | `ReactNode` | Yes | | Block 콘텐츠
|
|
1883
|
-
| `loading` | `boolean` | | | 로딩 상태. 설정 시 LoadingOverlay로 자동 래핑
|
|
1884
|
-
| `loadingLabel` | `string` | | | LoadingOverlay 접근성 레이블
|
|
1885
|
-
| `spacing` | `"section" \| "group" \| "element" \| "none"` | | "section" | Block 최상위 자식 사이 간격. 데이터 밀도가 높은 Block는 group/element로 낮출 수 있음
|
|
1886
|
-
| `
|
|
1892
|
+
| Prop | Type | Required | Default | Description |
|
|
1893
|
+
| -------------- | --------------------------------------------- | -------- | --------- | ---------------------------------------------------------------------------------------------------- |
|
|
1894
|
+
| `children` | `ReactNode` | Yes | | Block 콘텐츠 |
|
|
1895
|
+
| `loading` | `boolean` | | | 로딩 상태. 설정 시 LoadingOverlay로 자동 래핑 |
|
|
1896
|
+
| `loadingLabel` | `string` | | | LoadingOverlay 접근성 레이블 |
|
|
1897
|
+
| `spacing` | `"section" \| "group" \| "element" \| "none"` | | "section" | Block 최상위 자식 사이 간격. 데이터 밀도가 높은 Block는 group/element로 낮출 수 있음 |
|
|
1898
|
+
| `inset` | `"section" \| "group" \| "element" \| "none"` | | | Block 안쪽 여백. 페이지 콘텐츠 경계에는 section을 사용하고, 이미 여백을 제공하는 Shell 안에서는 생략 |
|
|
1899
|
+
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
1887
1900
|
|
|
1888
1901
|
**Examples:**
|
|
1889
1902
|
|
|
@@ -1892,7 +1905,7 @@ _Block 루트:_
|
|
|
1892
1905
|
```tsx
|
|
1893
1906
|
import { BlockLayout, PageHeader } from "@reopt-ai/opt-ui";
|
|
1894
1907
|
|
|
1895
|
-
<BlockLayout loading={isLoading} spacing="section">
|
|
1908
|
+
<BlockLayout loading={isLoading} spacing="section" inset="section">
|
|
1896
1909
|
<PageHeader title="대시보드" description="프로젝트 현황" />
|
|
1897
1910
|
<section>콘텐츠 영역</section>
|
|
1898
1911
|
</BlockLayout>;
|
|
@@ -2605,17 +2618,17 @@ const filters = [
|
|
|
2605
2618
|
**Import:** `import { FileUploadForm } from "@reopt-ai/opt-ui"`
|
|
2606
2619
|
**Dependencies:** form (core)
|
|
2607
2620
|
|
|
2608
|
-
| Prop | Type | Required | Default
|
|
2609
|
-
| ----------------- | ------------------------------------------------ | -------- |
|
|
2610
|
-
| `accept` | `string` | | "image
|
|
2611
|
-
| `showPreview` | `boolean` | | true
|
|
2612
|
-
| `showFileInfo` | `boolean` | | true
|
|
2613
|
-
| `showDescription` | `boolean` | | true
|
|
2614
|
-
| `maxFileSize` | `number` | |
|
|
2615
|
-
| `onSubmit` | `(values: { title, description, file }) => void` | |
|
|
2616
|
-
| `labels` | `FileUploadFormLabels` | |
|
|
2617
|
-
| `onPreview` | `(file: File) => void` | |
|
|
2618
|
-
| `columnMapping` | `ReactNode` | |
|
|
2621
|
+
| Prop | Type | Required | Default | Description |
|
|
2622
|
+
| ----------------- | ------------------------------------------------ | -------- | ------------------------- | ----------------------------------------- |
|
|
2623
|
+
| `accept` | `string` | | "image/*,.pdf,.doc,.docx" | 허용 파일 타입 |
|
|
2624
|
+
| `showPreview` | `boolean` | | true | 이미지 미리보기 표시 |
|
|
2625
|
+
| `showFileInfo` | `boolean` | | true | 파일 정보 표시 |
|
|
2626
|
+
| `showDescription` | `boolean` | | true | 설명 텍스트영역 표시 |
|
|
2627
|
+
| `maxFileSize` | `number` | | | 최대 파일 크기 (bytes) |
|
|
2628
|
+
| `onSubmit` | `(values: { title, description, file }) => void` | | | 제출 핸들러 |
|
|
2629
|
+
| `labels` | `FileUploadFormLabels` | | | i18n용 라벨 오버라이드 |
|
|
2630
|
+
| `onPreview` | `(file: File) => void` | | | 파일 선택 후 프리뷰 콜백 |
|
|
2631
|
+
| `columnMapping` | `ReactNode` | | | CSV 컬럼 매핑 UI 슬롯 (파일 선택 후 표시) |
|
|
2619
2632
|
|
|
2620
2633
|
#### EventIcon
|
|
2621
2634
|
|
|
@@ -2627,6 +2640,19 @@ const filters = [
|
|
|
2627
2640
|
| `color` | `string` | | theme accent | 사용자 지정 아이콘 색상. 없으면 theme accent 토큰을 사용하고, 전달하면 전경색과 tint 배경에 적용됩니다. |
|
|
2628
2641
|
| `size` | `"sm" \| "md" \| "lg"` | | "md" | 아이콘 크기 (sm=20px, md=28px, lg=36px) |
|
|
2629
2642
|
|
|
2643
|
+
#### ConnectionIndicator
|
|
2644
|
+
|
|
2645
|
+
**Import:** `import { ConnectionIndicator } from "@reopt-ai/opt-ui"`
|
|
2646
|
+
|
|
2647
|
+
| Prop | Type | Required | Default | Description |
|
|
2648
|
+
| ----------- | ----------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------- |
|
|
2649
|
+
| `status` | `"connected" \| "connecting" \| "disconnected" \| "error"` | | | 연결 상태 프리셋. tone과 pulse의 기본값을 정함 |
|
|
2650
|
+
| `tone` | `"neutral" \| "success" \| "warning" \| "danger" \| "info"` | | | status로 표현되지 않는 도메인 상태의 색을 직접 지정 (status보다 우선) |
|
|
2651
|
+
| `label` | `string` | | | 상태 문구 |
|
|
2652
|
+
| `showLabel` | `boolean` | | | 문구 표시 여부 |
|
|
2653
|
+
| `pulse` | `boolean` | | | 점 애니메이션. 생략하면 status 프리셋을 따름 |
|
|
2654
|
+
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
2655
|
+
|
|
2630
2656
|
#### TemplatePicker
|
|
2631
2657
|
|
|
2632
2658
|
**Import:** `import { TemplatePicker } from "@reopt-ai/opt-ui"`
|
|
@@ -2728,6 +2754,30 @@ const filters = [
|
|
|
2728
2754
|
| `error` | `string` | | | assertive 오류 상태 |
|
|
2729
2755
|
| `labels` | `QueryResultsTableLabels` | | | 로딩/빈 상태/행 수 문구 |
|
|
2730
2756
|
|
|
2757
|
+
#### SqlEditor
|
|
2758
|
+
|
|
2759
|
+
**Import:** `import { SqlEditor } from "@reopt-ai/opt-ui"`
|
|
2760
|
+
**Dependencies:** button (core)
|
|
2761
|
+
|
|
2762
|
+
| Prop | Type | Required | Default | Description |
|
|
2763
|
+
| ------------------- | ----------------------------- | -------- | ------- | -------------------------------------------------------------------------------- |
|
|
2764
|
+
| `value` | `string` | Yes | | 편집 중인 SQL |
|
|
2765
|
+
| `onChange` | `(sql: string) => void` | Yes | | 본문 변경 핸들러 |
|
|
2766
|
+
| `onRun` | `(sql: string) => void` | | | Mod+Enter 실행 핸들러 |
|
|
2767
|
+
| `onRunAndAdvance` | `(sql: string) => void` | | | Shift+Enter — 실행 후 다음 셀/탭으로 이동 |
|
|
2768
|
+
| `schema` | `SqlEditorSchema` | | | 테이블/컬럼 자동완성 스키마. 변경 시 에디터를 다시 만들지 않고 자동완성만 재구성 |
|
|
2769
|
+
| `completionSources` | `SqlEditorCompletionSource[]` | | | 스키마 자동완성에 더할 완성 소스 (함수 시그니처, 스니펫) |
|
|
2770
|
+
| `keymap` | `SqlEditorKeyBinding[]` | | | 추가 키 바인딩. 내장 실행 바인딩보다 먼저 평가 |
|
|
2771
|
+
| `extensions` | `SqlEditorExtension[]` | | | 임의의 CodeMirror 확장. 내장 확장 뒤에 붙어 우선권을 가짐 |
|
|
2772
|
+
| `height` | `number \| "fill"` | | | px 고정 높이. fill이면 부모가 정한 높이를 채움 |
|
|
2773
|
+
| `placeholder` | `string` | | | 빈 편집기 안내 문구 |
|
|
2774
|
+
| `readOnly` | `boolean` | | | 편집 잠금 |
|
|
2775
|
+
| `ariaLabel` | `string` | | | 편집 영역 접근성 레이블 |
|
|
2776
|
+
| `autoFocus` | `boolean` | | | 마운트 시 포커스 |
|
|
2777
|
+
| `showFooter` | `boolean` | | | 실행 힌트/버튼 표시. 기본값은 onRun이 있을 때 표시 |
|
|
2778
|
+
| `labels` | `SqlEditorLabels` | | | 문구 오버라이드 |
|
|
2779
|
+
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
2780
|
+
|
|
2731
2781
|
#### ReportBuilder
|
|
2732
2782
|
|
|
2733
2783
|
**Import:** `import { ReportBuilder } from "@reopt-ai/opt-ui"`
|
|
@@ -3242,4 +3292,82 @@ const messages = [
|
|
|
3242
3292
|
<ChatMessageList messages={messages} loading={false} />;
|
|
3243
3293
|
```
|
|
3244
3294
|
|
|
3295
|
+
#### TimeRangeControl
|
|
3296
|
+
|
|
3297
|
+
**Import:** `import { TimeRangeControl } from "@reopt-ai/opt-ui"`
|
|
3298
|
+
|
|
3299
|
+
| Prop | Type | Required | Default | Description |
|
|
3300
|
+
| ------------------- | -------------------------------- | -------- | ------- | ---------------------------------------- |
|
|
3301
|
+
| `value` | `TimeRange` | Yes | | { from, to } — date math 문자열 또는 ISO |
|
|
3302
|
+
| `onChange` | `(range: TimeRange) => void` | Yes | | 범위가 커밋되었을 때 호출 |
|
|
3303
|
+
| `presets` | `TimeRangePreset[]` | | | 자주 쓰는 범위 목록 |
|
|
3304
|
+
| `recentRanges` | `TimeRangePreset[]` | | | 최근 사용한 범위 (호출자 소유) |
|
|
3305
|
+
| `timeZone` | `string` | | | 라운딩·표시에 쓸 IANA 타임존 |
|
|
3306
|
+
| `showUpdateButton` | `boolean` | | true | 편집을 명시적으로 커밋 |
|
|
3307
|
+
| `showWindowButtons` | `boolean` | | true | 이전/다음 창, 확대/축소 버튼 |
|
|
3308
|
+
| `refresh` | `RefreshSetting` | | | { interval, paused } 자동 갱신 설정 |
|
|
3309
|
+
| `onRefresh` | `() => void \| Promise<unknown>` | | | 갱신 요청 — 프라미스가 끝난 뒤 다음 tick |
|
|
3310
|
+
|
|
3311
|
+
#### TimeSeriesPanel
|
|
3312
|
+
|
|
3313
|
+
**Import:** `import { TimeSeriesPanel } from "@reopt-ai/opt-ui"`
|
|
3314
|
+
|
|
3315
|
+
| Prop | Type | Required | Default | Description |
|
|
3316
|
+
| ------------------ | ---------------------------- | -------- | ------- | --------------------------------------------- |
|
|
3317
|
+
| `data` | `TimeSeriesPoint[]` | Yes | | 시계열 데이터 |
|
|
3318
|
+
| `series` | `TimeSeriesDef[]` | Yes | | 시리즈 정의 |
|
|
3319
|
+
| `range` | `TimeRange` | Yes | | 조회 구간 — 차트 축도 여기에 고정됩니다 |
|
|
3320
|
+
| `onRangeChange` | `(range: TimeRange) => void` | Yes | | 드래그 줌·컨트롤 변경으로 구간이 바뀔 때 호출 |
|
|
3321
|
+
| `showRangeControl` | `boolean` | | true | 헤더에 TimeRangeControl 렌더 |
|
|
3322
|
+
| `toggleableLegend` | `boolean` | | false | 범례 클릭으로 시리즈 숨김 |
|
|
3323
|
+
| `annotations` | `TimeSeriesAnnotation[]` | | | 시간축 마커/구간 |
|
|
3324
|
+
| `height` | `number` | | 280 | 차트 높이 |
|
|
3325
|
+
|
|
3326
|
+
#### LogTable
|
|
3327
|
+
|
|
3328
|
+
**Import:** `import { LogTable } from "@reopt-ai/opt-ui"`
|
|
3329
|
+
|
|
3330
|
+
| Prop | Type | Required | Default | Description |
|
|
3331
|
+
| ---------------- | ---------------------------------------- | -------- | -------- | -------------------------------- |
|
|
3332
|
+
| `rows` | `Row[]` | Yes | | 표시할 행 |
|
|
3333
|
+
| `columns` | `LogColumn<Row>[]` | Yes | | 컬럼 정의 (표시 중인 것만) |
|
|
3334
|
+
| `getRowId` | `(row: Row) => string` | Yes | | 행 식별자 |
|
|
3335
|
+
| `selectedId` | `string \| null` | | | 선택된 행 |
|
|
3336
|
+
| `onSelect` | `(id: string) => void` | | | 행 선택 |
|
|
3337
|
+
| `onLoadMore` | `() => void` | | | 다음 페이지 요청 |
|
|
3338
|
+
| `prepending` | `boolean` | | false | 상단에 행이 삽입되는 라이브 목록 |
|
|
3339
|
+
| `onFollowChange` | `(following: boolean) => void` | | | 최신 행 고정 여부 보고 |
|
|
3340
|
+
| `isNew` | `(row: Row) => boolean` | | | 방금 도착한 행 강조 |
|
|
3341
|
+
| `sort` | `LogSort \| null` | | | 정렬 상태 |
|
|
3342
|
+
| `onSortChange` | `(sort: LogSort) => void` | | | 헤더 클릭 정렬 |
|
|
3343
|
+
| `onCellAction` | `(action: LogCellAction) => void` | | | 셀 값 포함/제외 필터 |
|
|
3344
|
+
| `density` | `"compact" \| "normal" \| "comfortable"` | | "normal" | 행 높이와 글자 크기 |
|
|
3345
|
+
|
|
3346
|
+
#### QueryBar
|
|
3347
|
+
|
|
3348
|
+
**Import:** `import { QueryBar } from "@reopt-ai/opt-ui"`
|
|
3349
|
+
|
|
3350
|
+
| Prop | Type | Required | Default | Description |
|
|
3351
|
+
| ------------- | ------------------------ | -------- | ------- | ---------------------------- |
|
|
3352
|
+
| `value` | `Query` | Yes | | 파싱된 쿼리 |
|
|
3353
|
+
| `onChange` | `(query: Query) => void` | Yes | | 커밋 시 호출 (Enter·blur) |
|
|
3354
|
+
| `fields` | `QueryField[]` | | | 자동완성할 필드와 알려진 값 |
|
|
3355
|
+
| `showClauses` | `boolean` | | false | 절을 제거 가능한 칩으로 표시 |
|
|
3356
|
+
| `live` | `boolean` | | false | 키 입력마다 커밋 |
|
|
3357
|
+
|
|
3358
|
+
#### FieldSidebar
|
|
3359
|
+
|
|
3360
|
+
**Import:** `import { FieldSidebar } from "@reopt-ai/opt-ui"`
|
|
3361
|
+
|
|
3362
|
+
| Prop | Type | Required | Default | Description |
|
|
3363
|
+
| ----------------------- | ------------------------------------------------------------------------ | -------- | ------- | ------------------------------ |
|
|
3364
|
+
| `fields` | `FieldSummary[]` | Yes | | 필드 목록 |
|
|
3365
|
+
| `expandedField` | `string \| null` | | | 값을 펼친 필드 |
|
|
3366
|
+
| `onExpandedFieldChange` | `(field: string \| null) => void` | | | 펼침 전환 — 호출자가 값을 조회 |
|
|
3367
|
+
| `values` | `FieldValueCount[]` | | | 펼친 필드의 상위 값 |
|
|
3368
|
+
| `valuesLoading` | `boolean` | | false | 값 조회 중 |
|
|
3369
|
+
| `sampledRows` | `number` | | | 집계 대상 행 수 (분모) |
|
|
3370
|
+
| `onToggleColumn` | `(field: string, next: boolean) => void` | | | 컬럼 추가/제거 |
|
|
3371
|
+
| `onFilter` | `(field: string, value: string, intent: "include" \| "exclude") => void` | | | 값 기준 필터 |
|
|
3372
|
+
|
|
3245
3373
|
### Surface Layer
|
package/README.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
접근성 우선 UI 컴포넌트 라이브러리. opt-ui-primitives 기반 Core, 비즈니스 Shells, Surface/block layout primitives를 제공합니다. 페이지 템플릿 Surface는 `@reopt-ai/opt-cli` registry로 설치하며, 차트와 데이터 시각화 컴포넌트는 `@reopt-ai/opt-charts`로 분리되었습니다.
|
|
4
4
|
|
|
5
|
+
## 에이전트 스킬로 설정하기 (권장)
|
|
6
|
+
|
|
7
|
+
소비자 프로젝트 루트에서 전용 스킬을 설치합니다.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx skills add reopt-ai/reopt-skills/opt-ui-install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
설치 후 에이전트에게
|
|
14
|
+
`opt-ui-install 스킬로 이 프로젝트에 @reopt-ai/opt-ui를 설정하고 검증해줘`라고
|
|
15
|
+
요청하세요. 스킬은 신규 설치와 업그레이드를 구분하고, `AGENTS.md`(없으면
|
|
16
|
+
`CLAUDE.md`)의 reopt marker 블록, Tailwind v4, `OptThemeProvider`, `opt
|
|
17
|
+
doctor`, Surface 흐름을 멱등하게 설정합니다. 스킬 소스는
|
|
18
|
+
[`reopt-ai/reopt-skills`](https://github.com/reopt-ai/reopt-skills/tree/main/skills/opt-ui-install)가
|
|
19
|
+
단일 기준입니다.
|
|
20
|
+
|
|
21
|
+
아래 설치 명령은 스킬을 사용할 수 없거나 모든 단계를 직접 통제할 때의 수동
|
|
22
|
+
대안입니다.
|
|
23
|
+
|
|
5
24
|
## 설치
|
|
6
25
|
|
|
7
26
|
```bash
|
|
@@ -170,13 +189,15 @@ CSS 변수 기반 시맨틱 토큰 — `dark:` 프리픽스 없이 자동 전환
|
|
|
170
189
|
|
|
171
190
|
### 시맨틱 스페이싱
|
|
172
191
|
|
|
173
|
-
| CSS 변수 | Tailwind
|
|
174
|
-
| --------------------- |
|
|
175
|
-
| `--opt-space-section` | `gap-section` | 1.5rem (24px) |
|
|
176
|
-
| `--opt-space-group` | `gap-group`
|
|
177
|
-
| `--opt-space-element` | `gap-element` | 0.5rem (8px) |
|
|
192
|
+
| CSS 변수 | Tailwind | 값 |
|
|
193
|
+
| --------------------- | -------------------------- | ------------- |
|
|
194
|
+
| `--opt-space-section` | `gap-section`, `p-section` | 1.5rem (24px) |
|
|
195
|
+
| `--opt-space-group` | `gap-group`, `p-group` | 1rem (16px) |
|
|
196
|
+
| `--opt-space-element` | `gap-element`, `p-element` | 0.5rem (8px) |
|
|
178
197
|
|
|
179
|
-
|
|
198
|
+
Block 루트는 반드시 `BlockLayout`을 사용합니다. 페이지 콘텐츠 경계를 Block이 직접 맡을 때는
|
|
199
|
+
`inset="section"`을 지정하고, 카드나 Shell이 이미 여백을 제공하는 embedded Block에서는 inset을
|
|
200
|
+
생략합니다. `PageHeader`는 재사용 가능한 콘텐츠 헤더이므로 바깥 여백을 소유하지 않습니다.
|
|
180
201
|
|
|
181
202
|
## 접근성
|
|
182
203
|
|
|
@@ -229,7 +250,7 @@ bun run test:coverage
|
|
|
229
250
|
## Design Decisions
|
|
230
251
|
|
|
231
252
|
- **Layer metaphor**: Core → Shells는 opt-ui가 맡고, 페이지 템플릿 Surface는 opt-cli block registry로 설치
|
|
232
|
-
- **
|
|
253
|
+
- **BlockLayout 강제**: block template은 반드시 `BlockLayout` 또는 `createBlock`을 사용하고, 페이지 경계는 `inset="section"`으로 명시
|
|
233
254
|
- **Subpath exports**: `./core`, `./visuals`, `./shells` — 필요한 계층만 import 가능
|
|
234
255
|
- **Dual format**: ESM + CJS — 모든 번들러/런타임 호환
|
|
235
256
|
- **Source maps**: 디버깅을 위한 소스맵 포함
|
package/dist/app.css
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @reopt-ai/opt-ui — Application base layer (optional)
|
|
3
|
+
*
|
|
4
|
+
* `tailwind.css`가 토큰과 유틸리티를 준다면, 이 파일은 **앱 셸이 매번 다시 쓰는
|
|
5
|
+
* 규칙**을 준다. 실제 소비 프로젝트를 감사했을 때 아래 다섯 가지가 앱마다
|
|
6
|
+
* 손으로 재작성돼 있었고, 매번 조금씩 달랐다 — 커서 정책, opt-ui 밖 요소의
|
|
7
|
+
* 포커스 링, 사용자 모션 설정, 글자 크기 설정, 스킵 링크.
|
|
8
|
+
*
|
|
9
|
+
* Usage (consumer globals.css):
|
|
10
|
+
*
|
|
11
|
+
* @import "tailwindcss";
|
|
12
|
+
* @import "@reopt-ai/opt-ui/tailwind.css";
|
|
13
|
+
* @import "@reopt-ai/opt-ui/app.css";
|
|
14
|
+
*
|
|
15
|
+
* 선택 사항이다. 앱이 자기 규칙을 갖고 있다면 안 써도 되고, 여기 규칙은 전부
|
|
16
|
+
* `:where()`로 특이도 0이라 유틸리티 클래스가 항상 이긴다.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
@layer base {
|
|
20
|
+
/* ── Cursor ──
|
|
21
|
+
*
|
|
22
|
+
* 브라우저 기본값은 button에 `default`를 준다. 디자인 시스템을 쓰는 앱은
|
|
23
|
+
* 예외 없이 이걸 pointer로 되돌리는데, 그 목록을 손으로 관리하면 role 기반
|
|
24
|
+
* 요소(`[role="option"]`, `[role="treeitem"]`)가 빠지기 쉽다.
|
|
25
|
+
*
|
|
26
|
+
* opt-ui 컴포넌트는 자체 클래스로 커서를 지정하므로 여기 규칙과 무관하다.
|
|
27
|
+
* 이건 앱이 직접 쓰는 raw 요소를 위한 것이다. */
|
|
28
|
+
:where(
|
|
29
|
+
button:not(:disabled),
|
|
30
|
+
summary,
|
|
31
|
+
label[for],
|
|
32
|
+
select:not(:disabled),
|
|
33
|
+
a[href],
|
|
34
|
+
input:is(
|
|
35
|
+
[type="button"],
|
|
36
|
+
[type="submit"],
|
|
37
|
+
[type="reset"],
|
|
38
|
+
[type="checkbox"],
|
|
39
|
+
[type="radio"],
|
|
40
|
+
[type="file"],
|
|
41
|
+
[type="range"]
|
|
42
|
+
):not(:disabled),
|
|
43
|
+
[role="button"]:not([aria-disabled="true"]),
|
|
44
|
+
[role="tab"]:not([aria-disabled="true"]),
|
|
45
|
+
[role="menuitem"]:not([aria-disabled="true"]),
|
|
46
|
+
[role="menuitemcheckbox"]:not([aria-disabled="true"]),
|
|
47
|
+
[role="menuitemradio"]:not([aria-disabled="true"]),
|
|
48
|
+
[role="option"]:not([aria-disabled="true"]),
|
|
49
|
+
[role="switch"]:not([aria-disabled="true"]),
|
|
50
|
+
[role="checkbox"]:not([aria-disabled="true"]),
|
|
51
|
+
[role="radio"]:not([aria-disabled="true"]),
|
|
52
|
+
[role="treeitem"]:not([aria-disabled="true"])
|
|
53
|
+
) {
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:where(
|
|
58
|
+
button:disabled,
|
|
59
|
+
input:disabled,
|
|
60
|
+
select:disabled,
|
|
61
|
+
textarea:disabled,
|
|
62
|
+
[aria-disabled="true"]
|
|
63
|
+
) {
|
|
64
|
+
cursor: not-allowed;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ── Focus ──
|
|
68
|
+
*
|
|
69
|
+
* opt-ui 컴포넌트는 `data-opt-id`를 달고 자체 포커스 링을 갖는다. 앱이 직접
|
|
70
|
+
* 쓰는 raw button/link/summary에는 아무것도 없어서, 키보드 사용자가 앱 고유
|
|
71
|
+
* 영역에 들어가는 순간 포커스가 사라지곤 한다. 같은 링을 기본값으로 준다. */
|
|
72
|
+
:where(
|
|
73
|
+
button:not([data-opt-id]),
|
|
74
|
+
a[href]:not([data-opt-id]),
|
|
75
|
+
summary:not([data-opt-id]),
|
|
76
|
+
[tabindex]:not([tabindex="-1"]):not([data-opt-id])
|
|
77
|
+
):focus-visible {
|
|
78
|
+
outline: 2px solid var(--opt-ring);
|
|
79
|
+
outline-offset: 2px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ── User preference: text scale ──
|
|
83
|
+
*
|
|
84
|
+
* `<html data-text-scale="small|large">`로 루트 글자 크기를 조절한다. rem
|
|
85
|
+
* 기반 토큰이 전부 따라 움직이므로 레이아웃이 함께 확대/축소된다. */
|
|
86
|
+
html[data-text-scale="small"] {
|
|
87
|
+
font-size: 93.75%;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
html[data-text-scale="large"] {
|
|
91
|
+
font-size: 112.5%;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* ── User preference: motion ──
|
|
95
|
+
*
|
|
96
|
+
* `tailwind.css`가 시스템 `prefers-reduced-motion`을 이미 존중한다. 이건 앱
|
|
97
|
+
* 설정에서 사용자가 **시스템과 무관하게** 끈 경우를 위한 명시적 스코프다.
|
|
98
|
+
* `<html data-motion="reduced">` 또는 앱 셸 루트에 붙인다. */
|
|
99
|
+
[data-motion="reduced"],
|
|
100
|
+
[data-motion="reduced"] :where(*, *::before, *::after) {
|
|
101
|
+
animation-duration: 0.01ms !important;
|
|
102
|
+
animation-iteration-count: 1 !important;
|
|
103
|
+
transition-duration: 0.01ms !important;
|
|
104
|
+
scroll-behavior: auto !important;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@layer components {
|
|
109
|
+
/* ── Shortcut hints ──
|
|
110
|
+
*
|
|
111
|
+
* `<Kbd hint>`가 붙이는 클래스. 메뉴 항목 옆에 붙는 "⌘K" 같은 광고성 배지를
|
|
112
|
+
* 가리키며, 단축키 도움말 자체는 대상이 아니다.
|
|
113
|
+
*
|
|
114
|
+
* `<html data-shortcut-hints="hidden">`이면 사라진다 — 설정 값을 모든 호출
|
|
115
|
+
* 지점에 내려보내지 않고 "키보드 힌트 숨기기"를 구현하는 경로다.
|
|
116
|
+
* opt-shell의 `shortcutHints` 정책이 그 속성을 쓴다. */
|
|
117
|
+
[data-shortcut-hints="hidden"] .opt-shortcut-hint {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ── Skip link ──
|
|
122
|
+
*
|
|
123
|
+
* 키보드 사용자가 사이드바 전체를 Tab으로 통과하지 않고 본문으로 건너뛰는
|
|
124
|
+
* 링크. 포커스 전에는 화면 밖에 있다가 포커스되면 나타난다.
|
|
125
|
+
*
|
|
126
|
+
* <a class="opt-skip-link" href="#main">본문으로 건너뛰기</a>
|
|
127
|
+
*/
|
|
128
|
+
.opt-skip-link {
|
|
129
|
+
position: fixed;
|
|
130
|
+
z-index: 100;
|
|
131
|
+
top: var(--opt-space-element);
|
|
132
|
+
left: var(--opt-space-element);
|
|
133
|
+
padding: var(--opt-space-element) var(--opt-space-group);
|
|
134
|
+
border: 1px solid var(--opt-ring);
|
|
135
|
+
border-radius: var(--opt-radius-md);
|
|
136
|
+
color: var(--opt-text);
|
|
137
|
+
background: var(--opt-surface-overlay);
|
|
138
|
+
box-shadow: var(--opt-shadow-md);
|
|
139
|
+
text-decoration: none;
|
|
140
|
+
transform: translateY(calc(-100% - var(--opt-space-section)));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.opt-skip-link:focus {
|
|
144
|
+
transform: translateY(0);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/*
|
|
149
|
+
* A row that just arrived over a live connection fades its highlight out once.
|
|
150
|
+
* The eye catches what is new without the list turning into a light show —
|
|
151
|
+
* and readers who asked for less motion get the row without the flash.
|
|
152
|
+
*/
|
|
153
|
+
@keyframes opt-log-row-enter {
|
|
154
|
+
from {
|
|
155
|
+
background-color: var(--opt-accent-subtle, rgb(59 130 246 / 0.18));
|
|
156
|
+
}
|
|
157
|
+
to {
|
|
158
|
+
background-color: transparent;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.opt-log-row-enter {
|
|
163
|
+
animation: opt-log-row-enter 1.5s ease-out 1;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@media (prefers-reduced-motion: reduce) {
|
|
167
|
+
.opt-log-row-enter {
|
|
168
|
+
animation: none;
|
|
169
|
+
}
|
|
170
|
+
}
|