@reopt-ai/opt-ui 1.13.0 → 1.15.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/CHANGELOG.md +45 -0
- package/COMPONENT_CATALOG.md +644 -123
- package/README.md +35 -7
- package/dist/core/index.cjs +4 -4
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/docs/02-components/01-core.md +261 -58
- package/dist/docs/02-components/02-visuals.md +1 -1
- package/dist/docs/02-components/03-shells.md +391 -65
- package/dist/docs/02-components/04-surfaces.md +1 -1
- package/dist/docs/02-components/index.md +4 -4
- package/dist/id-registry.cjs +32 -0
- package/dist/id-registry.js +32 -0
- package/dist/id-registry.json +68 -0
- package/dist/index.cjs +1196 -427
- package/dist/index.d.cts +208 -19
- package/dist/index.d.ts +208 -19
- package/dist/index.js +1050 -295
- package/dist/{key-pad-menu-DMmbQ1jF.js → key-pad-menu-BCOeYvsH.js} +59 -67
- package/dist/{key-pad-menu-BOVu97bj.d.cts → key-pad-menu-CaIsTHB2.d.cts} +22 -9
- package/dist/{key-pad-menu-0KWOnELe.cjs → key-pad-menu-Jaqxhx9P.cjs} +57 -77
- package/dist/{key-pad-menu-NlZ9zNF8.d.ts → key-pad-menu-odAEycIX.d.ts} +22 -9
- package/dist/meta.cjs +877 -26
- package/dist/meta.js +877 -26
- package/dist/{field-sidebar-CRdToHRO.js → replay-player-layout-BVUNsUS1.js} +904 -203
- package/dist/{field-sidebar-CxxSK4JO.cjs → replay-player-layout-Cmzptq89.cjs} +944 -201
- package/dist/{field-sidebar-D-rwuN_w.d.cts → replay-player-layout-DpqdfdQ6.d.ts} +246 -3
- package/dist/{field-sidebar-Dz7J4ett.d.ts → replay-player-layout-DuZW-gFF.d.cts} +246 -3
- package/dist/shells/index.cjs +58 -52
- package/dist/shells/index.d.cts +2 -2
- package/dist/shells/index.d.ts +2 -2
- package/dist/shells/index.js +2 -2
- package/dist/{text-truncate-Bd-0WkSP.js → text-truncate-B-8nJgnu.js} +200 -101
- package/dist/{text-truncate-eMzvU_7k.d.cts → text-truncate-DOxUijpB.d.cts} +3 -30
- package/dist/{text-truncate-eMzvU_7k.d.ts → text-truncate-DOxUijpB.d.ts} +3 -30
- package/dist/{text-truncate-BeYW6XZu.cjs → text-truncate-gQhpMy-Z.cjs} +214 -97
- package/dist/theme/server.d.cts +2 -2
- package/dist/theme/server.d.ts +2 -2
- package/package.json +2 -2
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.15.0 -->
|
|
6
6
|
|
|
7
7
|
## Quick Stats
|
|
8
8
|
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
| --------- | ------- |
|
|
11
11
|
| Core | 74 |
|
|
12
12
|
| Visuals | 0 |
|
|
13
|
-
| Shells |
|
|
13
|
+
| Shells | 99 |
|
|
14
14
|
| Surfaces | 0 |
|
|
15
|
-
| **Total** | **
|
|
15
|
+
| **Total** | **173** |
|
|
16
16
|
|
|
17
17
|
## Component Selection Guide
|
|
18
18
|
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
| Component | Description | Key Exports |
|
|
212
212
|
| --------- | ----------- | ----------- |
|
|
213
213
|
|
|
214
|
-
## Shell Components (
|
|
214
|
+
## Shell Components (99)
|
|
215
215
|
|
|
216
216
|
### Navigation & Layout
|
|
217
217
|
|
|
@@ -343,35 +343,39 @@
|
|
|
343
343
|
|
|
344
344
|
### Other
|
|
345
345
|
|
|
346
|
-
| Component | Description | Key Exports
|
|
347
|
-
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
348
|
-
| PageAside | Sticky 페이지 사이드 aside chrome. 고정 너비 + header/body/footer 3-slot. | `PageAside`
|
|
349
|
-
| FailureList | 실패 목록 패널. severity별 색상 강조, 그룹핑, 액션 슬롯을 지원합니다. | `FailureList`
|
|
350
|
-
| KeyValueEditor | 키-값 쌍 편집기. 동적 행 추가/삭제, 비밀값 토글, 유효성 검사를 지원합니다. | `KeyValueEditor`
|
|
351
|
-
|
|
|
352
|
-
|
|
|
353
|
-
|
|
|
354
|
-
|
|
|
355
|
-
|
|
|
356
|
-
|
|
|
357
|
-
|
|
|
358
|
-
|
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
|
|
|
365
|
-
|
|
|
366
|
-
|
|
|
367
|
-
|
|
|
368
|
-
|
|
|
369
|
-
|
|
|
370
|
-
|
|
|
371
|
-
|
|
|
372
|
-
|
|
|
373
|
-
|
|
|
374
|
-
|
|
|
346
|
+
| Component | Description | Key Exports |
|
|
347
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
348
|
+
| PageAside | Sticky 페이지 사이드 aside chrome. 고정 너비 + header/body/footer 3-slot. | `PageAside` |
|
|
349
|
+
| FailureList | 실패 목록 패널. severity별 색상 강조, 그룹핑, 액션 슬롯을 지원합니다. | `FailureList` |
|
|
350
|
+
| KeyValueEditor | 키-값 쌍 편집기. 동적 행 추가/삭제, 비밀값 토글, 유효성 검사를 지원합니다. | `KeyValueEditor` |
|
|
351
|
+
| CriteriaBuilder | 도메인 무관 2단계 조건 트리 편집기. 그룹 AND/OR, 순서·복제·부정·오류를 셸이 맡고 조건 문장은 소비자가 Expression 칩으로 렌더링합니다. | `CriteriaBuilder`, `criteriaBuilderMove`, `criteriaBuilderDuplicate`, `criteriaBuilderRemove`, `criteriaBuilderInsert`, `criteriaBuilderRemoveGroup`, `criteriaBuilderDuplicateGroup`, `criteriaGroupLetter` |
|
|
352
|
+
| EventTimeline | 이벤트를 순서로 읽히게 하는 타임라인. 인접 이벤트 사이의 경과 시간을 라벨링하고, 속성 페이로드를 제자리에서 펼치며, 세션 단위 그룹핑을 지원한다. | `EventTimeline` |
|
|
353
|
+
| ScoreBreakdown | 합성 점수를 축별로 분해해 보여준다. 총점과 함께 각 축의 값·가중치·의미를 노출해 '43'을 판정이 아니라 발견으로 만든다. | `ScoreBreakdown` |
|
|
354
|
+
| Flyout | 목록을 화면에 둔 채 레코드를 옆에서 보여주는 상세 패널. 모달이 아니다 — 포커스 트랩·aria-modal·inert 없이 Escape로 닫고 포커스를 되돌린다. | `Flyout` |
|
|
355
|
+
| AuditTimeline | 변경 이력 타임라인. 액션별 색상 코딩 + 확장 가능한 diff 뷰. | `AuditTimeline` |
|
|
356
|
+
| ChatSidebar | AI 채팅 사이드바. 대화 목록, 검색, 새 대화 버튼. | `ChatSidebar` |
|
|
357
|
+
| ChatInput | 채팅 입력 컴포넌트. 자동 리사이즈 textarea, 파일 첨부, 모델/스타일 Select. | `ChatInput` |
|
|
358
|
+
| ChatMessageList | 채팅 메시지 목록. 역할별 말풍선, 타이핑 인디케이터, 자동 스크롤. | `ChatMessageList` |
|
|
359
|
+
| TimeRangeControl | date math(now-7d, now/d) 기반 시간 범위 컨트롤. quick select, 프리셋/최근 사용, 명시적 Update, 자동 갱신, 창 이동·확대/축소 버튼을 제공합니다. | `TimeRangeControl`, `DEFAULT_TIME_PRESETS` |
|
|
360
|
+
| TimeSeriesPanel | 시간 범위 컨트롤과 시계열 차트를 한 단위로 묶은 패널. 드래그 줌과 줌 히스토리(되돌리기), 범례 토글을 포함합니다. | `TimeSeriesPanel` |
|
|
361
|
+
| LogTable | 계속 도착하는 로그용 윈도잉 테이블. 컬럼 정의 기반, 상단 삽입 시 스크롤 위치 보존, follow 상태 보고, 셀 값 즉시 필터, 밀도·정렬을 지원합니다. | `LogTable` |
|
|
362
|
+
| QueryBar | 검색과 필터를 한 입력으로 합친 쿼리 바. field:value, -부정, (a or b), 비교 연산, 필드·값 자동완성, 절(clause) 칩을 지원합니다. | `QueryBar` |
|
|
363
|
+
| FieldSidebar | 데이터에 어떤 필드가 있고 각 필드가 무슨 값을 갖는지 보여주는 사이드바. 값 분포 막대, 컬럼으로 승격, 값 기준 포함/제외 필터를 제공합니다. | `FieldSidebar` |
|
|
364
|
+
| InspectorLayout | 목록과 인스펙터의 2-pane 레이아웃. 넓으면 밀어내고(push) 좁으면 덮으며(overlay), 닫을 때 포커스를 열었던 자리로 되돌립니다. | `InspectorLayout` |
|
|
365
|
+
| QueryFilterBar | QueryBar와 필터 버튼이 하나의 Query를 공유합니다. 버튼은 상태를 갖지 않고 Query를 읽어 활성 여부를 계산합니다. | `QueryFilterBar`, `hasActiveQuery` |
|
|
366
|
+
| CatalogFrame | 카탈로그 목록의 공통 뼈대. 헤더·통계·고지·필터·인스펙터·페이지네이션·일괄 작업과 빈/에러 상태를 담고, 필터나 페이지가 바뀌면 선택을 비웁니다. | `CatalogFrame`, `CatalogRowActions`, `CatalogCellControls` |
|
|
367
|
+
| SchemaTree | 쿼리할 수 있는 테이블과 컬럼을 타입 글리프와 함께 보여주는 트리. 테이블·컬럼을 함께 검색하고, 이름을 커서에 삽입하거나 테이블을 미리보기합니다. | `SchemaTree` |
|
|
368
|
+
| QueryToolbar | 실행 버튼 하나가 상태를 말하는 쿼리 툴바. 변경됨/현재/실행 중을 색과 문구로 구분하고, 실행 중이면 취소로 바뀌며, 선택 영역·전체 실행은 분할 버튼 뒤에 둡니다. | `QueryToolbar` |
|
|
369
|
+
| QueryOutputPane | 쿼리 결과가 놓이는 출력 패널. 대기·실행 중·오류·취소·완료 상태를 그리고, 완료는 표·차트·좌우 분할로 전환하며, 상태바에 행 수·경과·읽은 바이트·절단 여부를 남깁니다. | `QueryOutputPane` |
|
|
370
|
+
| QueryResultChart | 결과 행을 차트로 그리는 빌더. 첫 문자·날짜 컬럼을 축으로, 숫자 컬럼을 값으로 고르고, 한 행 한 숫자면 큰 숫자로 보여줍니다. 설정은 호출자가 들고 있어 저장 쿼리와 함께 보관됩니다. | `QueryResultChart` |
|
|
371
|
+
| QueryFiltersMenu | 기간과 속성 조건을 데이터로 들고 {filters} 플레이스홀더로 SQL에 전달하는 메뉴. 플레이스홀더가 없으면 조건이 적용되지 않는다고 경고하고 삽입 버튼을 제공합니다. | `QueryFiltersMenu` |
|
|
372
|
+
| QueryVariablesMenu | 실행마다 바뀌는 값을 이름 붙여 두는 변수 메뉴. SQL은 {variables.name}으로 참조하고 치환은 호출자가 합니다. | `QueryVariablesMenu` |
|
|
373
|
+
| QueryHistoryList | 실행 이력 목록. 각 실행의 성공/실패, 시각, 행 수, 경과를 보여주고 편집기로 되돌리거나 다시 실행합니다. | `QueryHistoryList` |
|
|
374
|
+
| SaveQueryDialog | 쿼리에 이름·설명·공개 여부를 붙여 저장하는 다이얼로그. 편집기에 문장이 여럿이면 어느 문장을 저장할지 넘겨 보며 고릅니다. | `SaveQueryDialog` |
|
|
375
|
+
| QueryWorkspace | 스키마·편집기·출력의 3-pane 쿼리 워크스페이스. 패널은 리사이즈되고 사이드바는 접히며, storageKey로 레이아웃을 기억합니다. 툴바·편집기·출력은 슬롯입니다. | `QueryWorkspace` |
|
|
376
|
+
| ReplayScrubber | 세션 리플레이의 탐색 트랙. 활동/비활성/미로딩 구간, 활동 밀도, 이벤트 마커를 한 플레이헤드 아래에 겹쳐 그리고, 드래그·키보드 탐색이 끝났을 때만 seek을 커밋한다. | `ReplayScrubber`, `groupReplayMarkers` |
|
|
377
|
+
| ReplayTransport | 세션 리플레이 재생 컨트롤. 재생/일시정지, 앞뒤 점프, 배속 메뉴, 비활성 건너뛰기 토글, 전체화면, 경과/시계 타임코드 전환을 제공하며 재생 상태는 호스트가 소유한다. | `ReplayTransport`, `formatReplayElapsed` |
|
|
378
|
+
| ReplayPlayerLayout | 세션 리플레이 플레이어의 프레임. 스테이지·메타 바·컨트롤·리사이즈 가능한 인스펙터를 배치하고, 플레이어 전체의 전체화면과 입력 필드를 피하는 키보드 단축키 범위를 소유한다. | `ReplayPlayerLayout`, `replayShortcutKey` |
|
|
375
379
|
|
|
376
380
|
## Surface Components (0)
|
|
377
381
|
|
|
@@ -532,19 +536,19 @@
|
|
|
532
536
|
|
|
533
537
|
**Import:** `import { InlineEdit } from "@reopt-ai/opt-ui"`
|
|
534
538
|
|
|
535
|
-
| Prop | Type | Required | Default | Description
|
|
536
|
-
| ------------- | --------------------------------------------------------------- | -------- | ---------- |
|
|
537
|
-
| `value` | `string` | Yes | | 현재 값
|
|
538
|
-
| `onSave` | `(next: string) => boolean \| void \| Promise<boolean \| void>` | Yes | | 저장. false
|
|
539
|
-
| `as` | `"span" \| "h1" \| "h2" \| "h3" \| "h4"` | | "span" | 읽기 모드 요소
|
|
540
|
-
| `size` | `"sm" \| "md" \| "lg" \| "xl"` | | "md" | 타이포 크기
|
|
541
|
-
| `placeholder` | `string` | | | 입력 자리표시자
|
|
542
|
-
| `emptyText` | `string` | | "Untitled" | 빈 값 표시
|
|
543
|
-
| `disabled` | `boolean` | | false | 편집 불가
|
|
544
|
-
| `maxLength` | `number` | | | 최대 길이
|
|
545
|
-
| `suffix` | `ReactNode` | | | 읽기 모드 텍스트 뒤 요소
|
|
546
|
-
| `labels` | `InlineEditLabels` | | |
|
|
547
|
-
| `className` | `string` | | | 추가 CSS 클래스
|
|
539
|
+
| Prop | Type | Required | Default | Description |
|
|
540
|
+
| ------------- | --------------------------------------------------------------- | -------- | ---------- | ----------------------------------------------------------------- |
|
|
541
|
+
| `value` | `string` | Yes | | 현재 값 |
|
|
542
|
+
| `onSave` | `(next: string) => boolean \| void \| Promise<boolean \| void>` | Yes | | 저장. false 반환 또는 Promise 실패 시 입력을 유지하고 오류를 알림 |
|
|
543
|
+
| `as` | `"span" \| "h1" \| "h2" \| "h3" \| "h4"` | | "span" | 읽기 모드 요소 |
|
|
544
|
+
| `size` | `"sm" \| "md" \| "lg" \| "xl"` | | "md" | 타이포 크기 |
|
|
545
|
+
| `placeholder` | `string` | | | 입력 자리표시자 |
|
|
546
|
+
| `emptyText` | `string` | | "Untitled" | 빈 값 표시 |
|
|
547
|
+
| `disabled` | `boolean` | | false | 편집 불가 |
|
|
548
|
+
| `maxLength` | `number` | | | 최대 길이 |
|
|
549
|
+
| `suffix` | `ReactNode` | | | 읽기 모드 텍스트 뒤 요소 |
|
|
550
|
+
| `labels` | `InlineEditLabels` | | | 입력 이름(input), 편집·저장·취소·오류 안내 문자열 |
|
|
551
|
+
| `className` | `string` | | | 추가 CSS 클래스 |
|
|
548
552
|
|
|
549
553
|
#### KeyPadMenu
|
|
550
554
|
|
|
@@ -739,7 +743,7 @@
|
|
|
739
743
|
| Prop | Type | Required | Default | Description |
|
|
740
744
|
| ------------- | ------------------------- | -------- | ------- | --------------------------------------------------------------------------------------- |
|
|
741
745
|
| `open` | `boolean` | | | 제어 모드: 열림 상태 |
|
|
742
|
-
| `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.
|
|
746
|
+
| `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onOpenChange` instead** |
|
|
743
747
|
| `defaultOpen` | `boolean` | | false | 비제어 모드: 초기 열림 상태 |
|
|
744
748
|
|
|
745
749
|
**DisclosureTrigger:**
|
|
@@ -773,7 +777,7 @@
|
|
|
773
777
|
| `variant` | `"underline" \| "workspace"` | | | 탭 프레임 형태. workspace는 편집기 탭(문서/쿼리처럼 열고 닫히며 상태를 갖는 작업 단위) |
|
|
774
778
|
| `defaultSelectedId` | `string` | | | 초기 선택된 탭 ID |
|
|
775
779
|
| `selectedId` | `string \| null` | | | 제어 모드: 선택된 탭 ID |
|
|
776
|
-
| `setSelectedId` | `(id: string \| null) => void` | | | 제어 모드: 탭 변경 핸들러 **⚠️ deprecated since 1.
|
|
780
|
+
| `setSelectedId` | `(id: string \| null) => void` | | | 제어 모드: 탭 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onSelectedIdChange` instead** |
|
|
777
781
|
|
|
778
782
|
**TabList:**
|
|
779
783
|
|
|
@@ -810,6 +814,27 @@
|
|
|
810
814
|
| `Home` | 첫 번째 탭으로 이동 |
|
|
811
815
|
| `End` | 마지막 탭으로 이동 |
|
|
812
816
|
|
|
817
|
+
**Examples:**
|
|
818
|
+
|
|
819
|
+
_이름 있는 두 패널:_
|
|
820
|
+
|
|
821
|
+
```tsx
|
|
822
|
+
import { TabsRoot, TabList, Tab, TabPanel } from "@reopt-ai/opt-ui";
|
|
823
|
+
|
|
824
|
+
export function Example() {
|
|
825
|
+
return (
|
|
826
|
+
<TabsRoot defaultSelectedId="overview">
|
|
827
|
+
<TabList aria-label="프로젝트 정보">
|
|
828
|
+
<Tab id="overview">개요</Tab>
|
|
829
|
+
<Tab id="activity">활동</Tab>
|
|
830
|
+
</TabList>
|
|
831
|
+
<TabPanel tabId="overview">프로젝트 요약</TabPanel>
|
|
832
|
+
<TabPanel tabId="activity">최근 활동</TabPanel>
|
|
833
|
+
</TabsRoot>
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
```
|
|
837
|
+
|
|
813
838
|
#### Select
|
|
814
839
|
|
|
815
840
|
**Import:** `import { SelectRoot } from "@reopt-ai/opt-ui"`
|
|
@@ -843,7 +868,7 @@
|
|
|
843
868
|
| ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
|
|
844
869
|
| `children` | `ReactNode` | Yes | | SelectItem 목록 |
|
|
845
870
|
| `sameWidth` | `boolean` | | true | 트리거와 같은 너비 |
|
|
846
|
-
| `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.
|
|
871
|
+
| `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
|
|
847
872
|
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
848
873
|
|
|
849
874
|
**SelectItem:**
|
|
@@ -896,7 +921,7 @@ import {
|
|
|
896
921
|
| Prop | Type | Required | Default | Description |
|
|
897
922
|
| --------- | ------------------------- | -------- | ------- | --------------------------------------------------------------------------------------- |
|
|
898
923
|
| `open` | `boolean` | | | 제어 모드: 열림 상태 |
|
|
899
|
-
| `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.
|
|
924
|
+
| `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onOpenChange` instead** |
|
|
900
925
|
|
|
901
926
|
**DialogDisclosure:**
|
|
902
927
|
|
|
@@ -988,7 +1013,7 @@ import {
|
|
|
988
1013
|
|
|
989
1014
|
| Prop | Type | Required | Default | Description |
|
|
990
1015
|
| ------------------ | ------------------------- | -------- | ------- | ------------------------------------------------------------------------------- |
|
|
991
|
-
| `setValue` | `(value: string) => void` | | | 입력값 변경 핸들러 **⚠️ deprecated since 1.
|
|
1016
|
+
| `setValue` | `(value: string) => void` | | | 입력값 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onValueChange` instead** |
|
|
992
1017
|
| `resetValueOnHide` | `boolean` | | false | 팝오버 닫힐 때 입력값 리셋 |
|
|
993
1018
|
|
|
994
1019
|
**ComboboxInput:**
|
|
@@ -1005,7 +1030,7 @@ import {
|
|
|
1005
1030
|
| ----------- | ----------- | -------- | ------- | ---------------------------------------------------------------------------- |
|
|
1006
1031
|
| `children` | `ReactNode` | Yes | | ComboboxItem/Group 목록 |
|
|
1007
1032
|
| `sameWidth` | `boolean` | | true | 입력과 같은 너비 |
|
|
1008
|
-
| `gutter` | `number` | | 4 | 입력과의 간격 (px) **⚠️ deprecated since 1.
|
|
1033
|
+
| `gutter` | `number` | | 4 | 입력과의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
|
|
1009
1034
|
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
1010
1035
|
|
|
1011
1036
|
**ComboboxItem:**
|
|
@@ -1083,7 +1108,7 @@ import {
|
|
|
1083
1108
|
| Prop | Type | Required | Default | Description |
|
|
1084
1109
|
| ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
|
|
1085
1110
|
| `children` | `ReactNode` | Yes | | MenuItem 목록 |
|
|
1086
|
-
| `gutter` | `number` | | 8 | 트리거와의 간격 (px) **⚠️ deprecated since 1.
|
|
1111
|
+
| `gutter` | `number` | | 8 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
|
|
1087
1112
|
| `className` | `string` | | | 기본 스타일 오버라이드 |
|
|
1088
1113
|
|
|
1089
1114
|
**MenuItem:**
|
|
@@ -1223,12 +1248,15 @@ import {
|
|
|
1223
1248
|
|
|
1224
1249
|
**FormSelect:**
|
|
1225
1250
|
|
|
1226
|
-
| Prop
|
|
1227
|
-
|
|
|
1228
|
-
| `
|
|
1229
|
-
| `
|
|
1230
|
-
| `
|
|
1231
|
-
| `
|
|
1251
|
+
| Prop | Type | Required | Default | Description |
|
|
1252
|
+
| ------------------ | ----------- | -------- | ------- | ------------------------------------------ |
|
|
1253
|
+
| `id` | `string` | | | 트리거 ID. 외부 FormLabel의 htmlFor와 연결 |
|
|
1254
|
+
| `aria-label` | `string` | | | 입력의 접근 가능한 이름 |
|
|
1255
|
+
| `aria-describedby` | `string` | | | 설명·오류 요소의 ID 목록 |
|
|
1256
|
+
| `name` | `string` | Yes | | 폼 필드 이름 |
|
|
1257
|
+
| `children` | `ReactNode` | Yes | | FormSelectPopover 등 자식 요소 |
|
|
1258
|
+
| `placeholder` | `string` | | | 미선택 시 표시 텍스트 |
|
|
1259
|
+
| `className` | `string` | | | 추가 CSS 클래스 |
|
|
1232
1260
|
|
|
1233
1261
|
**FormSelectPopover:**
|
|
1234
1262
|
|
|
@@ -1236,7 +1264,7 @@ import {
|
|
|
1236
1264
|
| ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
|
|
1237
1265
|
| `children` | `ReactNode` | Yes | | FormSelectItem 목록 |
|
|
1238
1266
|
| `sameWidth` | `boolean` | | true | 트리거와 같은 너비 |
|
|
1239
|
-
| `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.
|
|
1267
|
+
| `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
|
|
1240
1268
|
|
|
1241
1269
|
**FormSelectItem:**
|
|
1242
1270
|
|
|
@@ -1494,6 +1522,21 @@ import { Button } from "@reopt-ai/opt-ui";
|
|
|
1494
1522
|
| `progress` | `number` | | | 원형 프로그레스 값 (0-100). 설정 시 dot 무시 |
|
|
1495
1523
|
| `progressSize` | `number` | | 16 | 프로그레스 링 SVG 크기 (px) |
|
|
1496
1524
|
|
|
1525
|
+
**Examples:**
|
|
1526
|
+
|
|
1527
|
+
_텍스트가 있는 상태:_
|
|
1528
|
+
|
|
1529
|
+
```tsx
|
|
1530
|
+
import { Badge } from "@reopt-ai/opt-ui";
|
|
1531
|
+
export function Example() {
|
|
1532
|
+
return (
|
|
1533
|
+
<Badge variant="success" dot>
|
|
1534
|
+
동기화 완료
|
|
1535
|
+
</Badge>
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
```
|
|
1539
|
+
|
|
1497
1540
|
#### Spinner
|
|
1498
1541
|
|
|
1499
1542
|
**Import:** `import { Spinner } from "@reopt-ai/opt-ui"`
|
|
@@ -1502,6 +1545,17 @@ import { Button } from "@reopt-ai/opt-ui";
|
|
|
1502
1545
|
| ------ | ---------------------- | -------- | ------- | ----------- |
|
|
1503
1546
|
| `size` | `"sm" \| "md" \| "lg"` | | "md" | 스피너 크기 |
|
|
1504
1547
|
|
|
1548
|
+
**Examples:**
|
|
1549
|
+
|
|
1550
|
+
_이름 있는 로딩 표시:_
|
|
1551
|
+
|
|
1552
|
+
```tsx
|
|
1553
|
+
import { Spinner } from "@reopt-ai/opt-ui";
|
|
1554
|
+
export function Example() {
|
|
1555
|
+
return <Spinner size="sm" aria-label="검색 결과 불러오는 중" />;
|
|
1556
|
+
}
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1505
1559
|
#### Alert
|
|
1506
1560
|
|
|
1507
1561
|
**Import:** `import { Alert } from "@reopt-ai/opt-ui"`
|
|
@@ -1514,6 +1568,21 @@ import { Button } from "@reopt-ai/opt-ui";
|
|
|
1514
1568
|
| `dismissible` | `boolean` | | false | 닫기 버튼 표시 여부 |
|
|
1515
1569
|
| `onDismiss` | `() => void` | | | 닫기 버튼 클릭 핸들러 |
|
|
1516
1570
|
|
|
1571
|
+
**Examples:**
|
|
1572
|
+
|
|
1573
|
+
_재시도 가능한 오류 안내:_
|
|
1574
|
+
|
|
1575
|
+
```tsx
|
|
1576
|
+
import { Alert } from "@reopt-ai/opt-ui";
|
|
1577
|
+
export function Example() {
|
|
1578
|
+
return (
|
|
1579
|
+
<Alert variant="error" title="저장하지 못했습니다">
|
|
1580
|
+
연결 상태를 확인한 뒤 다시 저장하세요.
|
|
1581
|
+
</Alert>
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
```
|
|
1585
|
+
|
|
1517
1586
|
#### Input
|
|
1518
1587
|
|
|
1519
1588
|
**Import:** `import { Input } from "@reopt-ai/opt-ui"`
|
|
@@ -1582,6 +1651,27 @@ const store = useFormStore({ defaultValues: { name: "" } });
|
|
|
1582
1651
|
| `size` | `"sm" \| "md" \| "lg"` | | "md" | 스위치 크기 |
|
|
1583
1652
|
| `disabled` | `boolean` | | | 비활성화 상태 |
|
|
1584
1653
|
|
|
1654
|
+
**Examples:**
|
|
1655
|
+
|
|
1656
|
+
_제어되는 알림 설정:_
|
|
1657
|
+
|
|
1658
|
+
```tsx
|
|
1659
|
+
"use client";
|
|
1660
|
+
import { useState } from "react";
|
|
1661
|
+
import { Switch } from "@reopt-ai/opt-ui";
|
|
1662
|
+
export function Example() {
|
|
1663
|
+
const [enabled, setEnabled] = useState(false);
|
|
1664
|
+
return (
|
|
1665
|
+
<Switch
|
|
1666
|
+
label="이메일 알림"
|
|
1667
|
+
hint="새 댓글을 이메일로 받습니다"
|
|
1668
|
+
checked={enabled}
|
|
1669
|
+
onChange={setEnabled}
|
|
1670
|
+
/>
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
```
|
|
1674
|
+
|
|
1585
1675
|
#### Skeleton
|
|
1586
1676
|
|
|
1587
1677
|
**Import:** `import { Skeleton } from "@reopt-ai/opt-ui"`
|
|
@@ -1615,6 +1705,21 @@ const store = useFormStore({ defaultValues: { name: "" } });
|
|
|
1615
1705
|
| `rows` | `number` | | 5 | 테이블 행 수 |
|
|
1616
1706
|
| `columns` | `number` | | 4 | 테이블 열 수 |
|
|
1617
1707
|
|
|
1708
|
+
**Examples:**
|
|
1709
|
+
|
|
1710
|
+
_목록 로딩 자리 확보:_
|
|
1711
|
+
|
|
1712
|
+
```tsx
|
|
1713
|
+
import { SkeletonTable } from "@reopt-ai/opt-ui";
|
|
1714
|
+
export function Example() {
|
|
1715
|
+
return (
|
|
1716
|
+
<section aria-label="목록 불러오는 중" aria-busy="true">
|
|
1717
|
+
<SkeletonTable rows={3} columns={4} />
|
|
1718
|
+
</section>
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
```
|
|
1722
|
+
|
|
1618
1723
|
#### Textarea
|
|
1619
1724
|
|
|
1620
1725
|
**Import:** `import { Textarea } from "@reopt-ai/opt-ui"`
|
|
@@ -1628,6 +1733,25 @@ const store = useFormStore({ defaultValues: { name: "" } });
|
|
|
1628
1733
|
| `resize` | `"none" \| "vertical" \| "horizontal" \| "both"` | | "vertical" | 크기 조절 방향 |
|
|
1629
1734
|
| `rows` | `number` | | 4 | 표시 줄 수 |
|
|
1630
1735
|
|
|
1736
|
+
**Examples:**
|
|
1737
|
+
|
|
1738
|
+
_설명 입력:_
|
|
1739
|
+
|
|
1740
|
+
```tsx
|
|
1741
|
+
import { Textarea } from "@reopt-ai/opt-ui";
|
|
1742
|
+
export function Example() {
|
|
1743
|
+
return (
|
|
1744
|
+
<Textarea
|
|
1745
|
+
label="변경 이유"
|
|
1746
|
+
name="reason"
|
|
1747
|
+
hint="검토자가 알아야 할 내용을 적어주세요"
|
|
1748
|
+
rows={4}
|
|
1749
|
+
resize="vertical"
|
|
1750
|
+
/>
|
|
1751
|
+
);
|
|
1752
|
+
}
|
|
1753
|
+
```
|
|
1754
|
+
|
|
1631
1755
|
#### Avatar
|
|
1632
1756
|
|
|
1633
1757
|
**Import:** `import { Avatar } from "@reopt-ai/opt-ui"`
|
|
@@ -1651,6 +1775,22 @@ const store = useFormStore({ defaultValues: { name: "" } });
|
|
|
1651
1775
|
| `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | | "md" | 아바타 크기 |
|
|
1652
1776
|
| `children` | `ReactNode` | Yes | | Avatar 요소들 |
|
|
1653
1777
|
|
|
1778
|
+
**Examples:**
|
|
1779
|
+
|
|
1780
|
+
_이미지 없이 사용자 표시:_
|
|
1781
|
+
|
|
1782
|
+
```tsx
|
|
1783
|
+
import { Avatar, AvatarGroup } from "@reopt-ai/opt-ui";
|
|
1784
|
+
export function Example() {
|
|
1785
|
+
return (
|
|
1786
|
+
<AvatarGroup max={3}>
|
|
1787
|
+
<Avatar name="김민수" />
|
|
1788
|
+
<Avatar name="이지수" />
|
|
1789
|
+
</AvatarGroup>
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
```
|
|
1793
|
+
|
|
1654
1794
|
#### Progress
|
|
1655
1795
|
|
|
1656
1796
|
**Import:** `import { Progress } from "@reopt-ai/opt-ui"`
|
|
@@ -1681,6 +1821,17 @@ const store = useFormStore({ defaultValues: { name: "" } });
|
|
|
1681
1821
|
| `label` | `string` | | | 접근성 레이블 |
|
|
1682
1822
|
| `indeterminate` | `boolean` | | false | 값을 알 수 없는 진행 상태 |
|
|
1683
1823
|
|
|
1824
|
+
**Examples:**
|
|
1825
|
+
|
|
1826
|
+
_업로드 진행률:_
|
|
1827
|
+
|
|
1828
|
+
```tsx
|
|
1829
|
+
import { Progress } from "@reopt-ai/opt-ui";
|
|
1830
|
+
export function Example() {
|
|
1831
|
+
return <Progress value={35} max={100} aria-label="파일 업로드" />;
|
|
1832
|
+
}
|
|
1833
|
+
```
|
|
1834
|
+
|
|
1684
1835
|
#### Meter
|
|
1685
1836
|
|
|
1686
1837
|
**Import:** `import { Meter } from "@reopt-ai/opt-ui"`
|
|
@@ -1843,6 +1994,22 @@ import {
|
|
|
1843
1994
|
| `orientation` | `"horizontal" \| "vertical"` | | "vertical" | 레이아웃 방향 |
|
|
1844
1995
|
| `label` | `string` | | | 그룹 레이블 |
|
|
1845
1996
|
|
|
1997
|
+
**Examples:**
|
|
1998
|
+
|
|
1999
|
+
_복수 선택 그룹:_
|
|
2000
|
+
|
|
2001
|
+
```tsx
|
|
2002
|
+
import { Checkbox, CheckboxGroup } from "@reopt-ai/opt-ui";
|
|
2003
|
+
export function Example() {
|
|
2004
|
+
return (
|
|
2005
|
+
<CheckboxGroup label="알림 채널" defaultValue={["email"]}>
|
|
2006
|
+
<Checkbox value="email" label="이메일" />
|
|
2007
|
+
<Checkbox value="push" label="푸시" />
|
|
2008
|
+
</CheckboxGroup>
|
|
2009
|
+
);
|
|
2010
|
+
}
|
|
2011
|
+
```
|
|
2012
|
+
|
|
1846
2013
|
#### RadioGroup
|
|
1847
2014
|
|
|
1848
2015
|
**Import:** `import { RadioGroup } from "@reopt-ai/opt-ui"`
|
|
@@ -1962,27 +2129,27 @@ import {
|
|
|
1962
2129
|
|
|
1963
2130
|
**Import:** `import { ConditionBuilder } from "@reopt-ai/opt-ui"`
|
|
1964
2131
|
|
|
1965
|
-
| Prop | Type | Required | Default | Description
|
|
1966
|
-
| --------------------- | --------------------------------------- | -------- | ------------------ |
|
|
1967
|
-
| `groups` | `ConditionGroup[]` | Yes | | 조건 그룹 배열
|
|
1968
|
-
| `onChange` | `(groups: ConditionGroup[]) => void` | Yes | | 그룹 변경 핸들러
|
|
1969
|
-
| `properties` | `string[]` | | | 선택 가능한 속성 목록 (기본 10개 제공)
|
|
1970
|
-
| `label` | `string` | | | 빌더 레이블
|
|
1971
|
-
| `nested` | `boolean` | | false | 중첩 AND/OR 그룹 활성화
|
|
1972
|
-
| `maxDepth` | `number` | | 3 | 최대 중첩 깊이
|
|
1973
|
-
| `conditionTypes` | `Record<string, ConditionTypeRenderer>` | | | 이질적 조건 타입 렌더러 레지스트리
|
|
1974
|
-
| `onPreview` | `(groups: ConditionGroup[]) => void` | | | 조건 변경 시 미리보기 콜백
|
|
1975
|
-
| `previewCount` | `number` | | | 매치 카운트 표시 (toLocaleString 포맷)
|
|
1976
|
-
| `
|
|
2132
|
+
| Prop | Type | Required | Default | Description |
|
|
2133
|
+
| --------------------- | --------------------------------------- | -------- | ------------------ | ------------------------------------------------------------------------------ |
|
|
2134
|
+
| `groups` | `ConditionGroup[]` | Yes | | 조건 그룹 배열 |
|
|
2135
|
+
| `onChange` | `(groups: ConditionGroup[]) => void` | Yes | | 그룹 변경 핸들러 |
|
|
2136
|
+
| `properties` | `string[]` | | | 선택 가능한 속성 목록 (기본 10개 제공) |
|
|
2137
|
+
| `label` | `string` | | | 빌더 레이블 |
|
|
2138
|
+
| `nested` | `boolean` | | false | 중첩 AND/OR 그룹 활성화 |
|
|
2139
|
+
| `maxDepth` | `number` | | 3 | 최대 중첩 깊이 |
|
|
2140
|
+
| `conditionTypes` | `Record<string, ConditionTypeRenderer>` | | | 이질적 조건 타입 렌더러 레지스트리 |
|
|
2141
|
+
| `onPreview` | `(groups: ConditionGroup[]) => void` | | | 조건 변경 시 미리보기 콜백 |
|
|
2142
|
+
| `previewCount` | `number` | | | 매치 카운트 표시 (toLocaleString 포맷) |
|
|
2143
|
+
| `labels` | `ConditionBuilderLabels` | | | 미리보기 문구 오버라이드 (previewSuffix, formatPreview). 기본은 영어 "matches" |
|
|
2144
|
+
| `addNestedGroupLabel` | `string` | | "Add nested group" | 중첩 그룹 추가 버튼 텍스트 |
|
|
1977
2145
|
|
|
1978
2146
|
#### Popover
|
|
1979
2147
|
|
|
1980
2148
|
**Import:** `import { PopoverRoot } from "@reopt-ai/opt-ui"`
|
|
1981
2149
|
|
|
1982
|
-
| Prop | Type | Required | Default | Description
|
|
1983
|
-
| ----------- | -------- | -------- | ------- |
|
|
1984
|
-
| `
|
|
1985
|
-
| `className` | `string` | | | 커스텀 CSS 클래스 |
|
|
2150
|
+
| Prop | Type | Required | Default | Description |
|
|
2151
|
+
| ----------- | -------- | -------- | ------- | ----------------- |
|
|
2152
|
+
| `className` | `string` | | | 커스텀 CSS 클래스 |
|
|
1986
2153
|
|
|
1987
2154
|
**Keyboard Shortcuts:**
|
|
1988
2155
|
|
|
@@ -1991,6 +2158,30 @@ import {
|
|
|
1991
2158
|
| `Esc` | 팝오버 닫기 |
|
|
1992
2159
|
| `Enter / Space` | 트리거 활성화 |
|
|
1993
2160
|
|
|
2161
|
+
**Examples:**
|
|
2162
|
+
|
|
2163
|
+
_보조 설명 열고 닫기:_
|
|
2164
|
+
|
|
2165
|
+
```tsx
|
|
2166
|
+
import {
|
|
2167
|
+
PopoverRoot,
|
|
2168
|
+
PopoverTrigger,
|
|
2169
|
+
PopoverContent,
|
|
2170
|
+
PopoverClose,
|
|
2171
|
+
} from "@reopt-ai/opt-ui";
|
|
2172
|
+
export function Example() {
|
|
2173
|
+
return (
|
|
2174
|
+
<PopoverRoot>
|
|
2175
|
+
<PopoverTrigger>공유 안내</PopoverTrigger>
|
|
2176
|
+
<PopoverContent>
|
|
2177
|
+
<p>초대받은 사용자만 문서를 볼 수 있습니다.</p>
|
|
2178
|
+
<PopoverClose>닫기</PopoverClose>
|
|
2179
|
+
</PopoverContent>
|
|
2180
|
+
</PopoverRoot>
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
```
|
|
2184
|
+
|
|
1994
2185
|
#### DropdownMenu
|
|
1995
2186
|
|
|
1996
2187
|
**Import:** `import { DropdownMenu } from "@reopt-ai/opt-ui"`
|
|
@@ -1999,7 +2190,7 @@ import {
|
|
|
1999
2190
|
|
|
2000
2191
|
| Prop | Type | Required | Default | Description |
|
|
2001
2192
|
| -------- | -------- | -------- | ------- | ------------------------------------------------------------------------------ |
|
|
2002
|
-
| `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.
|
|
2193
|
+
| `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
|
|
2003
2194
|
|
|
2004
2195
|
**DropdownItem:**
|
|
2005
2196
|
|
|
@@ -2048,19 +2239,20 @@ import {
|
|
|
2048
2239
|
|
|
2049
2240
|
**Import:** `import { Slider } from "@reopt-ai/opt-ui"`
|
|
2050
2241
|
|
|
2051
|
-
| Prop
|
|
2052
|
-
|
|
|
2053
|
-
| `value`
|
|
2054
|
-
| `defaultValue`
|
|
2055
|
-
| `onChange`
|
|
2056
|
-
| `
|
|
2057
|
-
| `
|
|
2058
|
-
| `
|
|
2059
|
-
| `
|
|
2060
|
-
| `
|
|
2061
|
-
| `
|
|
2062
|
-
| `
|
|
2063
|
-
| `
|
|
2242
|
+
| Prop | Type | Required | Default | Description |
|
|
2243
|
+
| --------------- | --------------------------- | -------- | ------- | ----------------------------------------------------------------- |
|
|
2244
|
+
| `value` | `number` | | | 제어 모드 값 |
|
|
2245
|
+
| `defaultValue` | `number` | | 0 | 비제어 모드 초기값 |
|
|
2246
|
+
| `onChange` | `(value: number) => void` | | | 값 변경 핸들러 |
|
|
2247
|
+
| `onValueCommit` | `(value: number) => void` | | | 포인터·키보드 편집 완료 시 한 번 호출. 취소와 외부 값 갱신은 제외 |
|
|
2248
|
+
| `min` | `number` | | 0 | 최솟값 |
|
|
2249
|
+
| `max` | `number` | | 100 | 최댓값 |
|
|
2250
|
+
| `step` | `number` | | 1 | 증감 단위 |
|
|
2251
|
+
| `label` | `string` | | | 레이블 텍스트 |
|
|
2252
|
+
| `showValue` | `boolean` | | false | 현재 값 표시 여부 |
|
|
2253
|
+
| `formatValue` | `(value: number) => string` | | | 값 포맷 함수 |
|
|
2254
|
+
| `disabled` | `boolean` | | | 비활성화 |
|
|
2255
|
+
| `className` | `string` | | | 최외곽 CSS 클래스 |
|
|
2064
2256
|
|
|
2065
2257
|
#### PageHeader
|
|
2066
2258
|
|
|
@@ -2288,6 +2480,21 @@ const MyDashboard = createBlock<MyDashboardProps>(
|
|
|
2288
2480
|
| `children` | `ReactNode` | Yes | | 감싸는 콘텐츠 |
|
|
2289
2481
|
| `label` | `string` | | "Loading…" | 로딩 텍스트 |
|
|
2290
2482
|
|
|
2483
|
+
**Examples:**
|
|
2484
|
+
|
|
2485
|
+
_기존 결과를 유지하는 갱신 표시:_
|
|
2486
|
+
|
|
2487
|
+
```tsx
|
|
2488
|
+
import { LoadingOverlay } from "@reopt-ai/opt-ui";
|
|
2489
|
+
export function Example() {
|
|
2490
|
+
return (
|
|
2491
|
+
<LoadingOverlay loading label="목록 새로고침 중">
|
|
2492
|
+
<p>이전 조회 결과</p>
|
|
2493
|
+
</LoadingOverlay>
|
|
2494
|
+
);
|
|
2495
|
+
}
|
|
2496
|
+
```
|
|
2497
|
+
|
|
2291
2498
|
#### StarRating
|
|
2292
2499
|
|
|
2293
2500
|
**Import:** `import { StarRating } from "@reopt-ai/opt-ui"`
|
|
@@ -2555,10 +2762,10 @@ import { SearchCombobox } from "@reopt-ai/opt-ui";
|
|
|
2555
2762
|
**Import:** `import { SettingsForm } from "@reopt-ai/opt-ui"`
|
|
2556
2763
|
**Dependencies:** form (core), checkbox (core), radio-group (core), switch (core)
|
|
2557
2764
|
|
|
2558
|
-
| Prop | Type
|
|
2559
|
-
| ---------- |
|
|
2560
|
-
| `fields` | `FormFieldDef[]`
|
|
2561
|
-
| `onSubmit` | `(values: Record<string, unknown>) => void
|
|
2765
|
+
| Prop | Type | Required | Default | Description |
|
|
2766
|
+
| ---------- | ------------------------------------------------------------ | -------- | ------- | ----------------- |
|
|
2767
|
+
| `fields` | `FormFieldDef[]` | Yes | | 폼 필드 정의 배열 |
|
|
2768
|
+
| `onSubmit` | `(values: Record<string, unknown>) => void \| Promise<void>` | | | 제출 핸들러 |
|
|
2562
2769
|
|
|
2563
2770
|
**Examples:**
|
|
2564
2771
|
|
|
@@ -2779,6 +2986,24 @@ import { DataTable } from "@reopt-ai/opt-ui";
|
|
|
2779
2986
|
| `toast` | `ToastMessage` | Yes | | 토스트 메시지 객체 |
|
|
2780
2987
|
| `onDismiss` | `() => void` | Yes | | 닫기 핸들러 |
|
|
2781
2988
|
|
|
2989
|
+
**Examples:**
|
|
2990
|
+
|
|
2991
|
+
_사용자 동작의 결과 알림:_
|
|
2992
|
+
|
|
2993
|
+
```tsx
|
|
2994
|
+
"use client";
|
|
2995
|
+
import { Button, ToastProvider, toast } from "@reopt-ai/opt-ui";
|
|
2996
|
+
export function Example() {
|
|
2997
|
+
return (
|
|
2998
|
+
<ToastProvider>
|
|
2999
|
+
<Button onClick={() => toast.success("알림 동작을 확인했습니다")}>
|
|
3000
|
+
알림 테스트
|
|
3001
|
+
</Button>
|
|
3002
|
+
</ToastProvider>
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
```
|
|
3006
|
+
|
|
2782
3007
|
#### DesignGuidePanel
|
|
2783
3008
|
|
|
2784
3009
|
**Import:** `import { DesignGuidePanel } from "@reopt-ai/opt-ui"`
|
|
@@ -2904,29 +3129,29 @@ const filters = [
|
|
|
2904
3129
|
**Import:** `import { AuthForm } from "@reopt-ai/opt-ui"`
|
|
2905
3130
|
**Dependencies:** form (core)
|
|
2906
3131
|
|
|
2907
|
-
| Prop | Type
|
|
2908
|
-
| ------------------- |
|
|
2909
|
-
| `defaultMode` | `"login" \| "signup"`
|
|
2910
|
-
| `mode` | `"login" \| "signup"`
|
|
2911
|
-
| `onModeChange` | `(mode: "login" \| "signup") => void`
|
|
2912
|
-
| `showRememberMe` | `boolean`
|
|
2913
|
-
| `minPasswordLength` | `number`
|
|
2914
|
-
| `onSubmit` | `(values: { email: string; password: string; confirmPassword?: string; rememberMe?: boolean; mode: "login" \| "signup" }) => void
|
|
2915
|
-
| `labels` | `AuthFormLabels`
|
|
3132
|
+
| Prop | Type | Required | Default | Description |
|
|
3133
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | -------------------------------------------- |
|
|
3134
|
+
| `defaultMode` | `"login" \| "signup"` | | "login" | 초기 모드 (비제어) |
|
|
3135
|
+
| `mode` | `"login" \| "signup"` | | | 제어 모드: 현재 모드 |
|
|
3136
|
+
| `onModeChange` | `(mode: "login" \| "signup") => void` | | | 모드 변경 핸들러 |
|
|
3137
|
+
| `showRememberMe` | `boolean` | | true | 로그인 모드에서 '로그인 상태 유지' 표시 여부 |
|
|
3138
|
+
| `minPasswordLength` | `number` | | 8 | 비밀번호 최소 길이 |
|
|
3139
|
+
| `onSubmit` | `(values: { email: string; password: string; confirmPassword?: string; rememberMe?: boolean; mode: "login" \| "signup" }) => void \| Promise<void>` | | | 제출 핸들러 |
|
|
3140
|
+
| `labels` | `AuthFormLabels` | | | i18n용 라벨 오버라이드 |
|
|
2916
3141
|
|
|
2917
3142
|
#### WizardForm
|
|
2918
3143
|
|
|
2919
3144
|
**Import:** `import { WizardForm } from "@reopt-ai/opt-ui"`
|
|
2920
3145
|
**Dependencies:** form (core), checkbox (core), radio-group (core)
|
|
2921
3146
|
|
|
2922
|
-
| Prop | Type
|
|
2923
|
-
| -------------- |
|
|
2924
|
-
| `fields` | `FormFieldDef[]`
|
|
2925
|
-
| `steps` | `WizardStepDef[]`
|
|
2926
|
-
| `showReview` | `boolean`
|
|
2927
|
-
| `onSubmit` | `(values: Record<string, unknown>) => void
|
|
2928
|
-
| `onStepChange` | `(stepIndex: number) => void`
|
|
2929
|
-
| `labels` | `WizardFormLabels`
|
|
3147
|
+
| Prop | Type | Required | Default | Description |
|
|
3148
|
+
| -------------- | ------------------------------------------------------------ | -------- | ------- | ------------------------------------------ |
|
|
3149
|
+
| `fields` | `FormFieldDef[]` | Yes | | 폼 필드 정의 배열 |
|
|
3150
|
+
| `steps` | `WizardStepDef[]` | Yes | | 단계 정의. { id, label, fields: string[] } |
|
|
3151
|
+
| `showReview` | `boolean` | | true | 마지막 리뷰 단계 표시 여부 |
|
|
3152
|
+
| `onSubmit` | `(values: Record<string, unknown>) => void \| Promise<void>` | | | 제출 핸들러 |
|
|
3153
|
+
| `onStepChange` | `(stepIndex: number) => void` | | | 단계 변경 핸들러 |
|
|
3154
|
+
| `labels` | `WizardFormLabels` | | | i18n용 라벨 오버라이드 |
|
|
2930
3155
|
|
|
2931
3156
|
#### DynamicFieldForm
|
|
2932
3157
|
|
|
@@ -2940,7 +3165,7 @@ const filters = [
|
|
|
2940
3165
|
| `maxFields` | `number` | | | 최대 필드 수 |
|
|
2941
3166
|
| `fieldType` | `"text" \| "email" \| "url" \| "number"` | | "text" | 필드 입력 타입 |
|
|
2942
3167
|
| `validateField` | `(value: string, index: number) => string \| undefined` | | | 커스텀 필드 검증 함수 |
|
|
2943
|
-
| `onSubmit` | `(values: string[]) => void
|
|
3168
|
+
| `onSubmit` | `(values: string[]) => void \| Promise<void>` | | | 제출 핸들러 |
|
|
2944
3169
|
| `labels` | `DynamicFieldFormLabels` | | | i18n용 라벨 오버라이드 |
|
|
2945
3170
|
|
|
2946
3171
|
#### FileUploadForm
|
|
@@ -2948,17 +3173,17 @@ const filters = [
|
|
|
2948
3173
|
**Import:** `import { FileUploadForm } from "@reopt-ai/opt-ui"`
|
|
2949
3174
|
**Dependencies:** form (core)
|
|
2950
3175
|
|
|
2951
|
-
| Prop | Type
|
|
2952
|
-
| ----------------- |
|
|
2953
|
-
| `accept` | `string`
|
|
2954
|
-
| `showPreview` | `boolean`
|
|
2955
|
-
| `showFileInfo` | `boolean`
|
|
2956
|
-
| `showDescription` | `boolean`
|
|
2957
|
-
| `maxFileSize` | `number`
|
|
2958
|
-
| `onSubmit` | `(values: { title: string; description: string; file: File \| null }) => void
|
|
2959
|
-
| `labels` | `FileUploadFormLabels`
|
|
2960
|
-
| `onPreview` | `(file: File) => void`
|
|
2961
|
-
| `columnMapping` | `ReactNode`
|
|
3176
|
+
| Prop | Type | Required | Default | Description |
|
|
3177
|
+
| ----------------- | ----------------------------------------------------------------------------------------------- | -------- | ------------------------- | ----------------------------------------- |
|
|
3178
|
+
| `accept` | `string` | | "image/*,.pdf,.doc,.docx" | 허용 파일 타입 |
|
|
3179
|
+
| `showPreview` | `boolean` | | true | 이미지 미리보기 표시 |
|
|
3180
|
+
| `showFileInfo` | `boolean` | | true | 파일 정보 표시 |
|
|
3181
|
+
| `showDescription` | `boolean` | | true | 설명 텍스트영역 표시 |
|
|
3182
|
+
| `maxFileSize` | `number` | | | 최대 파일 크기 (bytes) |
|
|
3183
|
+
| `onSubmit` | `(values: { title: string; description: string; file: File \| null }) => void \| Promise<void>` | | | 제출 핸들러 |
|
|
3184
|
+
| `labels` | `FileUploadFormLabels` | | | i18n용 라벨 오버라이드 |
|
|
3185
|
+
| `onPreview` | `(file: File) => void` | | | 파일 선택 후 프리뷰 콜백 |
|
|
3186
|
+
| `columnMapping` | `ReactNode` | | | CSV 컬럼 매핑 UI 슬롯 (파일 선택 후 표시) |
|
|
2962
3187
|
|
|
2963
3188
|
#### EventIcon
|
|
2964
3189
|
|
|
@@ -3187,6 +3412,103 @@ const filters = [
|
|
|
3187
3412
|
| `onCancel` | `() => void` | | | 취소 콜백 |
|
|
3188
3413
|
| `labels` | `ReportBuilderLabels` | | | UI 텍스트 커스터마이징 |
|
|
3189
3414
|
|
|
3415
|
+
#### CriteriaBuilder
|
|
3416
|
+
|
|
3417
|
+
**Import:** `import { CriteriaBuilder } from "@reopt-ai/opt-ui"`
|
|
3418
|
+
**Dependencies:** segmented-control (core), dropdown-menu (core), button (core), callout (core), empty-state (core), kbd (core)
|
|
3419
|
+
|
|
3420
|
+
| Prop | Type | Required | Default | Description |
|
|
3421
|
+
| --------------------- | -------------------------------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------ |
|
|
3422
|
+
| `value` | `CriteriaBuilderValue<TCriterion>` | Yes | | 조건 트리. { logic, groups: [{ id, logic, criteria }] } |
|
|
3423
|
+
| `onChange` | `(next: CriteriaBuilderValue<TCriterion>) => void` | Yes | | 트리 변경 핸들러 |
|
|
3424
|
+
| `kinds` | `CriteriaBuilderKindOption[]` | Yes | | 조건 추가 메뉴 항목. group으로 섹션을 나누고 negatedLabel이 있으면 부정 항목을 따로 냅니다 |
|
|
3425
|
+
| `createCriterion` | `(kind: string, negate: boolean) => TCriterion` | Yes | | 메뉴 선택으로 만들 초기 조건. 고유 id를 돌려줘야 합니다 |
|
|
3426
|
+
| `renderCriterion` | `(criterion: TCriterion, api: CriteriaRenderApi<TCriterion>) => React.ReactNode` | Yes | | 조건 한 줄의 편집 가능한 문장 렌더러 |
|
|
3427
|
+
| `cloneCriterion` | `(criterion: TCriterion) => TCriterion` | | | 복제 시 만들 사본. 기본은 새 id를 붙인 얕은 복사 |
|
|
3428
|
+
| `createGroupId` | `() => string` | | | 셸이 만드는 그룹의 id. 기본 group-N |
|
|
3429
|
+
| `errors` | `Record<string, string>` | | | 조건 id 또는 그룹 id별 오류 메시지 |
|
|
3430
|
+
| `maxGroups` | `number` | | 10 | 그룹 최대 수 |
|
|
3431
|
+
| `maxCriteriaPerGroup` | `number` | | 20 | 그룹당 조건 최대 수 |
|
|
3432
|
+
| `allowNegation` | `boolean` | | true | 조건별 부정 토글 표시 |
|
|
3433
|
+
| `disabled` | `boolean` | | false | 전체 비활성화 |
|
|
3434
|
+
| `aside` | `React.ReactNode` | | | 넓은 화면에서 트리 옆, 좁은 화면에서 아래에 놓이는 미리보기 슬롯 |
|
|
3435
|
+
| `labels` | `CriteriaBuilderLabels` | | | i18n용 라벨 오버라이드 (기본 한국어) |
|
|
3436
|
+
| `className` | `string` | | | 루트 CSS 클래스 |
|
|
3437
|
+
| `aria-label` | `string` | | | 빌더 접근성 이름 |
|
|
3438
|
+
|
|
3439
|
+
**Keyboard Shortcuts:**
|
|
3440
|
+
|
|
3441
|
+
| Keys | Action |
|
|
3442
|
+
| ---- | ----------------------------------- |
|
|
3443
|
+
| `A` | 포커스된 그룹에 조건 추가 메뉴 열기 |
|
|
3444
|
+
| `G` | 그룹 추가 |
|
|
3445
|
+
|
|
3446
|
+
**Examples:**
|
|
3447
|
+
|
|
3448
|
+
_이벤트 조건 세그먼트:_
|
|
3449
|
+
|
|
3450
|
+
```tsx
|
|
3451
|
+
"use client";
|
|
3452
|
+
import { useState } from "react";
|
|
3453
|
+
import {
|
|
3454
|
+
CriteriaBuilder,
|
|
3455
|
+
Expression,
|
|
3456
|
+
ExpressionGroup,
|
|
3457
|
+
type CriteriaBuilderValue,
|
|
3458
|
+
} from "@reopt-ai/opt-ui";
|
|
3459
|
+
|
|
3460
|
+
interface Criterion {
|
|
3461
|
+
id: string;
|
|
3462
|
+
kind: string;
|
|
3463
|
+
negate?: boolean;
|
|
3464
|
+
event: string;
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
let seq = 0;
|
|
3468
|
+
|
|
3469
|
+
export function Example() {
|
|
3470
|
+
const [value, setValue] = useState<CriteriaBuilderValue<Criterion>>({
|
|
3471
|
+
logic: "and",
|
|
3472
|
+
groups: [
|
|
3473
|
+
{
|
|
3474
|
+
id: "g1",
|
|
3475
|
+
logic: "and",
|
|
3476
|
+
criteria: [{ id: "c1", kind: "performed", event: "purchase" }],
|
|
3477
|
+
},
|
|
3478
|
+
],
|
|
3479
|
+
});
|
|
3480
|
+
return (
|
|
3481
|
+
<CriteriaBuilder
|
|
3482
|
+
value={value}
|
|
3483
|
+
onChange={setValue}
|
|
3484
|
+
kinds={[
|
|
3485
|
+
{
|
|
3486
|
+
kind: "performed",
|
|
3487
|
+
label: "이벤트를 수행함",
|
|
3488
|
+
negatedLabel: "이벤트를 수행하지 않음",
|
|
3489
|
+
},
|
|
3490
|
+
]}
|
|
3491
|
+
createCriterion={(kind, negate) => ({
|
|
3492
|
+
id: `c${++seq}`,
|
|
3493
|
+
kind,
|
|
3494
|
+
negate,
|
|
3495
|
+
event: "",
|
|
3496
|
+
})}
|
|
3497
|
+
renderCriterion={(criterion, api) => (
|
|
3498
|
+
<ExpressionGroup>
|
|
3499
|
+
<Expression
|
|
3500
|
+
description={criterion.negate ? "수행하지 않음" : "수행함"}
|
|
3501
|
+
value={criterion.event || "이벤트 선택"}
|
|
3502
|
+
invalid={api.invalid || criterion.event === ""}
|
|
3503
|
+
onClick={() => api.update({ event: "purchase" })}
|
|
3504
|
+
/>
|
|
3505
|
+
</ExpressionGroup>
|
|
3506
|
+
)}
|
|
3507
|
+
/>
|
|
3508
|
+
);
|
|
3509
|
+
}
|
|
3510
|
+
```
|
|
3511
|
+
|
|
3190
3512
|
#### InsightsPanel
|
|
3191
3513
|
|
|
3192
3514
|
**Import:** `import { InsightsPanel } from "@reopt-ai/opt-ui"`
|
|
@@ -3213,6 +3535,27 @@ const filters = [
|
|
|
3213
3535
|
| `presets` | `TimePresetDef[]` | | | 빠른 프리셋 목록 (Today, Last 7d 등) |
|
|
3214
3536
|
| `labels` | `TimeRangeSelectorLabels` | | | i18n용 라벨 오버라이드 |
|
|
3215
3537
|
|
|
3538
|
+
**Examples:**
|
|
3539
|
+
|
|
3540
|
+
_제어되는 조회 기간:_
|
|
3541
|
+
|
|
3542
|
+
```tsx
|
|
3543
|
+
"use client";
|
|
3544
|
+
import { useState } from "react";
|
|
3545
|
+
import { TimeRangeSelector, type DateRange } from "@reopt-ai/opt-ui";
|
|
3546
|
+
export function Example() {
|
|
3547
|
+
const [range, setRange] = useState<DateRange>({ start: null, end: null });
|
|
3548
|
+
return (
|
|
3549
|
+
<TimeRangeSelector
|
|
3550
|
+
value={range}
|
|
3551
|
+
onChange={setRange}
|
|
3552
|
+
labels={{ title: "조회 기간", placeholder: "기간 선택" }}
|
|
3553
|
+
presets={[{ label: "최근 7일", days: 7 }]}
|
|
3554
|
+
/>
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
```
|
|
3558
|
+
|
|
3216
3559
|
#### ExportButton
|
|
3217
3560
|
|
|
3218
3561
|
**Import:** `import { ExportButton } from "@reopt-ai/opt-ui"`
|
|
@@ -3243,6 +3586,38 @@ const filters = [
|
|
|
3243
3586
|
| `percentageFractionDigits` | `number` | | 1 | percentage 포맷 시 소수점 자리수 |
|
|
3244
3587
|
| `loading` | `boolean` | | false | 로딩 시 스켈레톤 표시 |
|
|
3245
3588
|
|
|
3589
|
+
**Examples:**
|
|
3590
|
+
|
|
3591
|
+
_의미가 다른 통계 비교:_
|
|
3592
|
+
|
|
3593
|
+
```tsx
|
|
3594
|
+
import { SummaryRow } from "@reopt-ai/opt-ui";
|
|
3595
|
+
export function Example() {
|
|
3596
|
+
return (
|
|
3597
|
+
<SummaryRow
|
|
3598
|
+
columns={2}
|
|
3599
|
+
stats={[
|
|
3600
|
+
{
|
|
3601
|
+
id: "orders",
|
|
3602
|
+
title: "주문",
|
|
3603
|
+
value: "120",
|
|
3604
|
+
change: "+10%",
|
|
3605
|
+
trend: "up",
|
|
3606
|
+
},
|
|
3607
|
+
{
|
|
3608
|
+
id: "errors",
|
|
3609
|
+
title: "오류",
|
|
3610
|
+
value: "2",
|
|
3611
|
+
change: "-50%",
|
|
3612
|
+
trend: "down",
|
|
3613
|
+
polarity: "negative",
|
|
3614
|
+
},
|
|
3615
|
+
]}
|
|
3616
|
+
/>
|
|
3617
|
+
);
|
|
3618
|
+
}
|
|
3619
|
+
```
|
|
3620
|
+
|
|
3246
3621
|
#### EventTimeline
|
|
3247
3622
|
|
|
3248
3623
|
**Import:** `import { EventTimeline } from "@reopt-ai/opt-ui"`
|
|
@@ -4116,4 +4491,150 @@ const messages = [
|
|
|
4116
4491
|
| `defaultEditorSize` | `number` | | 40 | 편집기 높이(%) |
|
|
4117
4492
|
| `labels` | `QueryWorkspaceLabels` | | | 문구 오버라이드 |
|
|
4118
4493
|
|
|
4494
|
+
#### ReplayScrubber
|
|
4495
|
+
|
|
4496
|
+
**Import:** `import { ReplayScrubber } from "@reopt-ai/opt-ui"`
|
|
4497
|
+
|
|
4498
|
+
| Prop | Type | Required | Default | Description |
|
|
4499
|
+
| ---------------- | ---------------------------------------- | -------- | ------- | ----------------------------------------------------------- |
|
|
4500
|
+
| `start` | `number` | Yes | | 재생 가능한 첫 시각(절대값, 보통 epoch ms) |
|
|
4501
|
+
| `end` | `number` | Yes | | 재생 가능한 마지막 시각 |
|
|
4502
|
+
| `position` | `number` | Yes | | 현재 플레이헤드. [start, end]로 클램프 |
|
|
4503
|
+
| `segments` | `ReplayScrubberSegment[]` | | | 활동 분류 구간. active/inactive/gap/buffer |
|
|
4504
|
+
| `buffered` | `Array<{ start: number; end: number }>` | | | 이미 로드된 범위 |
|
|
4505
|
+
| `activity` | `number[]` | | | 0..1로 정규화한 활동 밀도 버킷. 로그 스케일 영역으로 그린다 |
|
|
4506
|
+
| `markers` | `ReplayScrubberMarker[]` | | | 트랙 위 관심 지점. 가까운 마커는 하나로 합쳐진다 |
|
|
4507
|
+
| `onSeek` | `(time: number) => void` | Yes | | 포인터·키보드 조작이 끝났을 때 한 번 호출 |
|
|
4508
|
+
| `onPreview` | `(time: number \| null) => void` | | | 드래그·호버 중 미리보기 시각. 비싼 seek에 쓰지 않는다 |
|
|
4509
|
+
| `onMarkerSelect` | `(marker: ReplayScrubberMarker) => void` | | | 마커 선택. 생략하면 해당 시각으로 seek |
|
|
4510
|
+
| `formatTime` | `(time: number) => string` | | | 배지와 aria-valuetext 포맷. 기본 start 기준 m:ss |
|
|
4511
|
+
| `stepMs` | `number` | | 5000 | 화살표 키 이동량 |
|
|
4512
|
+
| `largeStepMs` | `number` | | 30000 | PageUp/PageDown·Shift+화살표 이동량 |
|
|
4513
|
+
| `disabled` | `boolean` | | false | 모든 조작을 비활성화 |
|
|
4514
|
+
| `labels` | `ReplayScrubberLabels` | | | 접근성 문구 오버라이드 |
|
|
4515
|
+
| `className` | `string` | | | 추가 클래스 |
|
|
4516
|
+
|
|
4517
|
+
**Examples:**
|
|
4518
|
+
|
|
4519
|
+
_구간·마커가 있는 탐색 트랙:_
|
|
4520
|
+
|
|
4521
|
+
```tsx
|
|
4522
|
+
import { ReplayScrubber } from "@reopt-ai/opt-ui";
|
|
4523
|
+
|
|
4524
|
+
<ReplayScrubber
|
|
4525
|
+
start={recording.start}
|
|
4526
|
+
end={recording.end}
|
|
4527
|
+
position={playhead}
|
|
4528
|
+
segments={[
|
|
4529
|
+
{ start: recording.start, end: recording.start + 60_000, kind: "active" },
|
|
4530
|
+
{ start: recording.start + 60_000, end: recording.end, kind: "inactive" },
|
|
4531
|
+
]}
|
|
4532
|
+
markers={[{ id: "err", time: errorAt, label: "TypeError", tone: "danger" }]}
|
|
4533
|
+
onSeek={(time) => player.seek(time)}
|
|
4534
|
+
labels={{ track: "녹화 탐색" }}
|
|
4535
|
+
/>;
|
|
4536
|
+
```
|
|
4537
|
+
|
|
4538
|
+
#### ReplayTransport
|
|
4539
|
+
|
|
4540
|
+
**Import:** `import { ReplayTransport } from "@reopt-ai/opt-ui"`
|
|
4541
|
+
|
|
4542
|
+
| Prop | Type | Required | Default | Description |
|
|
4543
|
+
| ---------------------- | -------------------------------------- | -------- | ----------------------------- | ---------------------------------------------- |
|
|
4544
|
+
| `playing` | `boolean` | Yes | | 재생 중 여부 |
|
|
4545
|
+
| `ended` | `boolean` | | false | 끝에 도달. 재생 버튼이 다시 시작을 제안 |
|
|
4546
|
+
| `position` | `number` | Yes | | 절대 플레이헤드 시각 |
|
|
4547
|
+
| `start` | `number` | Yes | | 녹화 시작 시각(절대값) |
|
|
4548
|
+
| `end` | `number` | Yes | | 녹화 종료 시각(절대값) |
|
|
4549
|
+
| `onTogglePlay` | `() => void` | Yes | | 재생/일시정지 토글. ended면 처음부터 다시 시작 |
|
|
4550
|
+
| `onSkip` | `(deltaMs: number) => void` | Yes | | 부호 있는 시간만큼 이동 |
|
|
4551
|
+
| `onSkipToStart` | `() => void` | | | 처음으로. 생략하면 버튼 숨김 |
|
|
4552
|
+
| `jumpMs` | `number` | | 10000 | 앞뒤 점프 버튼 이동량(ms) |
|
|
4553
|
+
| `speed` | `number` | Yes | | 현재 배속 |
|
|
4554
|
+
| `speeds` | `readonly number[]` | | [0.5, 1, 1.5, 2, 3, 4, 8, 16] | 선택 가능한 배속 목록 |
|
|
4555
|
+
| `onSpeedChange` | `(speed: number) => void` | Yes | | 배속 변경 콜백 |
|
|
4556
|
+
| `skipInactive` | `boolean` | Yes | | 비활성 구간 건너뛰기 여부 |
|
|
4557
|
+
| `onSkipInactiveChange` | `(skip: boolean) => void` | Yes | | 건너뛰기 토글 콜백 |
|
|
4558
|
+
| `fullscreen` | `boolean` | | | 전체화면 상태(호스트 소유) |
|
|
4559
|
+
| `onFullscreenChange` | `(fullscreen: boolean) => void` | | | 있으면 전체화면 버튼 표시 |
|
|
4560
|
+
| `timecode` | `"elapsed" \| "clock"` | | "elapsed" | 경과 시간 또는 실제 시각 표시 모드 |
|
|
4561
|
+
| `onTimecodeChange` | `(mode: "elapsed" \| "clock") => void` | | | 있으면 타임코드를 클릭해 전환 |
|
|
4562
|
+
| `formatClock` | `(time: number) => string` | | | clock 모드 포맷 |
|
|
4563
|
+
| `disabled` | `boolean` | | false | 모든 조작을 비활성화 |
|
|
4564
|
+
| `children` | `ReactNode` | | | 오른쪽에 추가 컨트롤 |
|
|
4565
|
+
| `labels` | `ReplayTransportLabels` | | | 문구 오버라이드 |
|
|
4566
|
+
| `shortcuts` | `ReplayTransportShortcuts` | | | 툴팁에 표시할 단축키 |
|
|
4567
|
+
| `className` | `string` | | | 추가 클래스 |
|
|
4568
|
+
|
|
4569
|
+
**Examples:**
|
|
4570
|
+
|
|
4571
|
+
_호스트가 재생 상태를 소유하는 트랜스포트:_
|
|
4572
|
+
|
|
4573
|
+
```tsx
|
|
4574
|
+
import { ReplayTransport } from "@reopt-ai/opt-ui";
|
|
4575
|
+
|
|
4576
|
+
<ReplayTransport
|
|
4577
|
+
playing={playing}
|
|
4578
|
+
position={playhead}
|
|
4579
|
+
start={recording.start}
|
|
4580
|
+
end={recording.end}
|
|
4581
|
+
onTogglePlay={() => (playing ? player.pause() : player.play())}
|
|
4582
|
+
onSkip={(delta) => player.seek(playhead + delta)}
|
|
4583
|
+
speed={speed}
|
|
4584
|
+
onSpeedChange={setSpeed}
|
|
4585
|
+
skipInactive={skipInactive}
|
|
4586
|
+
onSkipInactiveChange={setSkipInactive}
|
|
4587
|
+
labels={{ play: "재생", pause: "일시정지" }}
|
|
4588
|
+
/>;
|
|
4589
|
+
```
|
|
4590
|
+
|
|
4591
|
+
#### ReplayPlayerLayout
|
|
4592
|
+
|
|
4593
|
+
**Import:** `import { ReplayPlayerLayout } from "@reopt-ai/opt-ui"`
|
|
4594
|
+
|
|
4595
|
+
| Prop | Type | Required | Default | Description |
|
|
4596
|
+
| ----------------------- | ------------------------------- | -------- | ------- | -------------------------------------------------------------------- |
|
|
4597
|
+
| `stage` | `ReactNode` | Yes | | 녹화가 렌더되는 영역(iframe 호스트) |
|
|
4598
|
+
| `meta` | `ReactNode` | | | 스테이지 위 얇은 바: URL, 창, 기기 |
|
|
4599
|
+
| `controls` | `ReactNode` | | | 스테이지 아래 트랜스포트와 스크러버 |
|
|
4600
|
+
| `inspector` | `ReactNode` | | | 측면 패널. 생략하면 패널 없음 |
|
|
4601
|
+
| `inspectorOpen` | `boolean` | | true | 인스펙터 표시 여부(제어됨) |
|
|
4602
|
+
| `onInspectorOpenChange` | `(open: boolean) => void` | | | 있으면 토글 버튼 표시 |
|
|
4603
|
+
| `inspectorSize` | `number` | | 34 | 인스펙터 초기 폭(%) |
|
|
4604
|
+
| `layoutId` | `string` | | | 리사이즈 레이아웃 영속 id |
|
|
4605
|
+
| `fullscreen` | `boolean` | | false | 전체화면 상태(호스트 소유) |
|
|
4606
|
+
| `onFullscreenChange` | `(fullscreen: boolean) => void` | | | 전체화면 변경 콜백. 브라우저가 스스로 나가도 호출된다 |
|
|
4607
|
+
| `shortcuts` | `ReplayShortcutMap` | | | 포커스가 안에 있고 입력 필드가 아닐 때만 동작. false를 반환하면 전파 |
|
|
4608
|
+
| `overlay` | `ReactNode` | | | 스테이지 위 오버레이: 로딩, 오류, 건너뛰는 중 |
|
|
4609
|
+
| `labels` | `ReplayPlayerLayoutLabels` | | | 문구 오버라이드 |
|
|
4610
|
+
| `className` | `string` | | | 추가 클래스 |
|
|
4611
|
+
|
|
4612
|
+
**Examples:**
|
|
4613
|
+
|
|
4614
|
+
_스테이지·컨트롤·인스펙터 배치와 단축키:_
|
|
4615
|
+
|
|
4616
|
+
```tsx
|
|
4617
|
+
import { ReplayPlayerLayout } from "@reopt-ai/opt-ui";
|
|
4618
|
+
|
|
4619
|
+
<ReplayPlayerLayout
|
|
4620
|
+
layoutId="replay-player"
|
|
4621
|
+
meta={<span>{currentPath}</span>}
|
|
4622
|
+
stage={<div ref={stageRef} />}
|
|
4623
|
+
controls={
|
|
4624
|
+
<>
|
|
4625
|
+
{scrubber}
|
|
4626
|
+
{transport}
|
|
4627
|
+
</>
|
|
4628
|
+
}
|
|
4629
|
+
inspector={<EventList onSelect={(e) => player.seek(e.time)} />}
|
|
4630
|
+
inspectorOpen={inspectorOpen}
|
|
4631
|
+
onInspectorOpenChange={setInspectorOpen}
|
|
4632
|
+
shortcuts={{
|
|
4633
|
+
space: togglePlay,
|
|
4634
|
+
arrowleft: () => skip(-10_000),
|
|
4635
|
+
arrowright: () => skip(10_000),
|
|
4636
|
+
}}
|
|
4637
|
+
/>;
|
|
4638
|
+
```
|
|
4639
|
+
|
|
4119
4640
|
### Surface Layer
|