sellmate-design-system-react 9.0.0-beta.44 → 9.0.0-beta.46
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/AGENTS.md +107 -4
- package/dist/components/SButton/README.md +2 -0
- package/dist/components/SChatInput/README.md +44 -0
- package/dist/components/SChatInput/SChatInput.d.ts +60 -0
- package/dist/components/SChatInput/index.d.ts +1 -0
- package/dist/components/SChatMessage/README.md +81 -0
- package/dist/components/SChatMessage/SChatMessage.d.ts +102 -0
- package/dist/components/SChatMessage/index.d.ts +1 -0
- package/dist/components/SFooter/README.md +13 -8
- package/dist/components/SFooter/SFooter.d.ts +14 -9
- package/dist/components/SGhostButton/README.md +2 -0
- package/dist/components/SIcon/README.md +2 -0
- package/dist/components/SIcon/icons.gen.d.ts +1 -0
- package/dist/components/SImage/README.md +5 -0
- package/dist/components/SLoginCard/README.md +34 -0
- package/dist/components/SLoginCard/SLoginCard.d.ts +28 -0
- package/dist/components/SLoginCard/index.d.ts +1 -0
- package/dist/components/SLoginCard/sellmate-wordmark.d.ts +13 -0
- package/dist/components/SPopup/README.md +5 -6
- package/dist/components/SPopup/SPopup.d.ts +6 -7
- package/dist/components/SSelect/README.md +8 -0
- package/dist/components/SSelect/SSelect.d.ts +44 -0
- package/dist/components/SSelect/row-metrics.d.ts +60 -0
- package/dist/components/SSelect/select.config.d.ts +15 -0
- package/dist/components/STextarea/README.md +6 -1
- package/dist/components/STextarea/STextarea.d.ts +25 -2
- package/dist/index.cjs +9036 -8350
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +9059 -8379
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +293 -19
- package/dist/llms.txt +109 -6
- package/dist/styles.css +89 -0
- package/package.json +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# SLoginCard
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SLoginCard
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `product` | `ReactNode` | — | 로고 아래 제품명 (예: `AI assistant` · `account` · `chat`) |
|
|
12
|
+
| `title` | `ReactNode` | — | 제품을 한 줄로 소개하는 문장 |
|
|
13
|
+
| `description?` | `ReactNode` | — | 소개 문장 바로 아래 붙는 보조 설명. 소개와 한 덩어리로 읽힌다 |
|
|
14
|
+
| `footerNote?` | `ReactNode` | — | 버튼 아래 안내 문구 (예: 계정 발급 문의 안내) |
|
|
15
|
+
|
|
16
|
+
#### Events
|
|
17
|
+
|
|
18
|
+
| Event | Type | Description |
|
|
19
|
+
|-------|------|-------------|
|
|
20
|
+
| `onLogin` | `() => void` | 로그인 버튼을 눌렀을 때. 버튼 자체는 카드가 그리므로 **동작만 넘긴다** — 문구·색·크기는 세 제품에서 같아야 해서 카드가 쥐고 있다. |
|
|
21
|
+
|
|
22
|
+
## Dependencies
|
|
23
|
+
|
|
24
|
+
### Depends on
|
|
25
|
+
|
|
26
|
+
- [SButton](../SButton)
|
|
27
|
+
|
|
28
|
+
### Graph
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
graph TD;
|
|
32
|
+
SLoginCard --> SButton
|
|
33
|
+
style SLoginCard fill:#f9f,stroke:#333,stroke-width:4px
|
|
34
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export interface SLoginCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
3
|
+
/** 로고 아래 제품명 (예: `AI assistant` · `account` · `chat`) */
|
|
4
|
+
product: ReactNode;
|
|
5
|
+
/** 제품을 한 줄로 소개하는 문장 */
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
/** 소개 문장 바로 아래 붙는 보조 설명. 소개와 한 덩어리로 읽힌다 */
|
|
8
|
+
description?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* 로그인 버튼을 눌렀을 때. 버튼 자체는 카드가 그리므로 **동작만 넘긴다** —
|
|
11
|
+
* 문구·색·크기는 세 제품에서 같아야 해서 카드가 쥐고 있다.
|
|
12
|
+
*/
|
|
13
|
+
onLogin?: () => void;
|
|
14
|
+
/** 버튼 아래 안내 문구 (예: 계정 발급 문의 안내) */
|
|
15
|
+
footerNote?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* SLoginCard — 통합 계정 로그인 화면의 카드.
|
|
19
|
+
*
|
|
20
|
+
* 로고·제품명·소개·로그인 버튼·안내 문구를 세로 가운데로 세운다. 제품마다 다른 것은 문구뿐이라
|
|
21
|
+
* 문구와 로그인 동작만 prop 으로 받고 로고·버튼·간격·타이포·색은 카드가 쥔다.
|
|
22
|
+
*
|
|
23
|
+
* **크기는 부모가 정한다** — 폭은 368~640px 사이에서 부모를 채우고, 높이도 부모가 준 만큼 채운다.
|
|
24
|
+
*
|
|
25
|
+
* **카드는 화면을 잡지 않는다** — 회색 바탕과 가운데 정렬은 앱이 만드는 한 겹이다 (AGENTS.md §4-6).
|
|
26
|
+
* 덕분에 로그인 화면 밖(세션 만료 재인증 등)에서도 같은 카드를 그대로 쓸 수 있다.
|
|
27
|
+
*/
|
|
28
|
+
export declare const SLoginCard: import("react").ForwardRefExoticComponent<SLoginCardProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SLoginCard, type SLoginCardProps } from './SLoginCard';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal
|
|
3
|
+
* Sellmate 워드마크 — 로그인 카드의 기본 로고.
|
|
4
|
+
*
|
|
5
|
+
* 색(`#00275F`)은 **브랜드 자산의 일부**라 토큰을 거치지 않는다. 대응하는 색 토큰이 없고
|
|
6
|
+
* (가장 가까운 `--color-primary-90` 도 `#002B5E` 로 다른 색이다), 있더라도 로고 색은
|
|
7
|
+
* 테마를 따라 바뀌면 안 되는 값이다. `scripts/check-hardcoded.mjs` 의 ALLOW 에 등록해 둔다.
|
|
8
|
+
*
|
|
9
|
+
* 원본 비율은 276×40 이다. 크기를 바꾸려면 `className` 으로 높이만 주고 폭은 비율에 맡긴다.
|
|
10
|
+
*/
|
|
11
|
+
export declare function SellmateWordmark({ className }: {
|
|
12
|
+
className?: string;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
@@ -35,12 +35,11 @@ export type SPopupType = 'default' | 'light';
|
|
|
35
35
|
### SPopupSubmitButton
|
|
36
36
|
|
|
37
37
|
```ts
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
38
|
+
/**
|
|
39
|
+
* 확인 버튼 설정 — `SButton` 의 prop 을 그대로 받되 `onClick` 만 뺀다.
|
|
40
|
+
* 클릭은 `onSubmit` 이 전담하므로, 여기로도 받으면 조용히 덮어써지는 prop 이 생긴다.
|
|
41
|
+
*/
|
|
42
|
+
export type SPopupSubmitButton = Omit<SFooterButton, 'onClick'>;
|
|
44
43
|
```
|
|
45
44
|
|
|
46
45
|
### SPopupBodyPadding
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { type ReactNode, type CSSProperties } from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type SFooterButton } from '../SFooter';
|
|
3
3
|
export type SPopupType = 'default' | 'light';
|
|
4
4
|
export type SPopupBodyPadding = 'default' | 'none';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
5
|
+
/**
|
|
6
|
+
* 확인 버튼 설정 — `SButton` 의 prop 을 그대로 받되 `onClick` 만 뺀다.
|
|
7
|
+
* 클릭은 `onSubmit` 이 전담하므로, 여기로도 받으면 조용히 덮어써지는 prop 이 생긴다.
|
|
8
|
+
*/
|
|
9
|
+
export type SPopupSubmitButton = Omit<SFooterButton, 'onClick'>;
|
|
11
10
|
export interface SPopupProps {
|
|
12
11
|
/** 헤더 제목 */
|
|
13
12
|
popupTitle?: string;
|
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
| `dropdownHeight?` | `string` | `'640px'` | 드롭다운 최대 높이. 기본 640px — 창이 이보다 작으면 창 안에 남는 만큼까지만 채워진다 |
|
|
26
26
|
| `dropdownWidth?` | `string` | — | 드롭다운 너비 (없으면 트리거 너비). 창보다 넓게 줘도 창 폭까지만 벌어진다. |
|
|
27
27
|
| `maxDropdownWidth?` | `string` | `'640px'` | 드롭다운 최대 너비. 창이 이보다 좁으면 창 폭이 상한이 된다. |
|
|
28
|
+
| `virtualBuffer?` | `number` | `DEFAULT_VIRTUAL_BUFFER` | 화면 위·아래로 더 그려둘 여유 행 수 — 빠르게 스크롤할 때 빈 칸이 보이지 않게 한다. 목록은 **언제나 보이는 범위만 렌더한다**(끄는 prop 은 없다). 그래서 여는 비용이 옵션 수와 무관하고, 이 값만이 DOM 에 남는 행 수를 정한다 — 한 화면 분량 + 앞뒤로 이만큼. |
|
|
29
|
+
| `reachEndThreshold?` | `number` | `DEFAULT_REACH_END_THRESHOLD` | 목록 끝에서 이만큼 행이 남았을 때 `onReachEnd` 를 부른다 — 스크롤이 바닥에 닿기 전에 미리 받아 둔다. **한 페이지 크기보다 충분히 작게 잡는다.** 한 페이지가 드롭다운을 채우고도 이 문턱만큼 남기지 못하면, 페이지가 도착하는 족족 다음 페이지를 다시 청하게 된다 — 사용자가 스크롤을 하지 않아도 목록 전체를 받아 오므로 페이징을 한 의미가 사라진다. (한 페이지 50개 · 드롭다운에 20행이 보인다면 남는 것은 30행이므로, 문턱은 그보다 작아야 한다) |
|
|
30
|
+
| `hasMore?` | `boolean` | `false` | 더 받아올 페이지가 남았는가. `false` 면 `onReachEnd` 를 더 부르지 않는다 |
|
|
31
|
+
| `loading?` | `boolean` | `false` | 다음 페이지를 받는 중 — 목록 하단에 로딩 표시를 내고, 그동안 `onReachEnd` 를 다시 부르지 않는다 |
|
|
32
|
+
| `serverSearch?` | `boolean` | `false` | 검색을 서버로 넘긴다 — 내부 필터링을 하지 않고 `options` 를 받은 그대로 보여준다. `onSearchChange` 로 온 검색어에 맞는 목록을 소비 앱이 다시 내려줘야 한다. 켜면 검색바가 옵션 수와 무관하게 항상 나온다 — 검색 결과가 줄었다고 검색바가 사라지면 검색어를 지울 수단이 없어지기 때문이다. |
|
|
33
|
+
| `searchDebounce?` | `number` | `DEFAULT_SEARCH_DEBOUNCE` | `serverSearch` 에서 검색어를 서버로 넘기기 전 기다리는 시간(ms) |
|
|
28
34
|
| `label?` | `string` | — | |
|
|
29
35
|
| `labelWidth?` | `number \| string` | — | |
|
|
30
36
|
| `icon?` | `SIconName` | — | 레이블 영역 아이콘 |
|
|
@@ -44,6 +50,8 @@
|
|
|
44
50
|
|-------|------|-------------|
|
|
45
51
|
| `onValueChange` | `(value: any) => void` | 값 변경. 기본은 SSelectOption(들)이 오고, `valueAsPrimitive` 면 원시값이 온다 |
|
|
46
52
|
| `onOpenChange` | `(open: boolean) => void` | 열림/닫힘 변경 (sdDropDownShow) |
|
|
53
|
+
| `onReachEnd` | `() => void` | 목록 끝이 가까워지면 부른다 — 다음 페이지를 받아 `options` 뒤에 이어붙이라는 신호다. `hasMore` 가 `false` 이거나 `loading` 중이면 부르지 않고, 같은 목록 길이로 두 번 부르지 않는다. **`options` 는 갈아끼우지 말고 이어붙인다.** depth 타입이면 이미 있는 그룹의 `children` 에 이어야 한다 — 같은 그룹을 새 항목으로 또 밀어 넣으면 목록에 같은 헤더가 두 번 뜬다. 아직 받지 않은 옵션은 라벨을 알 수 없다. 그래서 이 prop 을 쓰는 화면은 `valueAsPrimitive` 를 켜지 않는 편이 안전하다 — 기본값(옵션 객체)이면 선택값이 라벨을 함께 들고 다녀서, 그 옵션이 목록에서 사라져도 트리거에 이름이 그대로 남는다. |
|
|
54
|
+
| `onSearchChange` | `(query: string) => void` | 검색어 변경. `serverSearch` 면 `searchDebounce` 만큼 묶어서 온다 |
|
|
47
55
|
|
|
48
56
|
#### Methods (ref)
|
|
49
57
|
|
|
@@ -63,6 +63,50 @@ export interface SSelectProps {
|
|
|
63
63
|
dropdownWidth?: string;
|
|
64
64
|
/** 드롭다운 최대 너비. 창이 이보다 좁으면 창 폭이 상한이 된다. */
|
|
65
65
|
maxDropdownWidth?: string;
|
|
66
|
+
/**
|
|
67
|
+
* 화면 위·아래로 더 그려둘 여유 행 수 — 빠르게 스크롤할 때 빈 칸이 보이지 않게 한다.
|
|
68
|
+
*
|
|
69
|
+
* 목록은 **언제나 보이는 범위만 렌더한다**(끄는 prop 은 없다). 그래서 여는 비용이 옵션
|
|
70
|
+
* 수와 무관하고, 이 값만이 DOM 에 남는 행 수를 정한다 — 한 화면 분량 + 앞뒤로 이만큼.
|
|
71
|
+
*/
|
|
72
|
+
virtualBuffer?: number;
|
|
73
|
+
/**
|
|
74
|
+
* 목록 끝이 가까워지면 부른다 — 다음 페이지를 받아 `options` 뒤에 이어붙이라는 신호다.
|
|
75
|
+
* `hasMore` 가 `false` 이거나 `loading` 중이면 부르지 않고, 같은 목록 길이로 두 번 부르지 않는다.
|
|
76
|
+
*
|
|
77
|
+
* **`options` 는 갈아끼우지 말고 이어붙인다.** depth 타입이면 이미 있는 그룹의 `children`
|
|
78
|
+
* 에 이어야 한다 — 같은 그룹을 새 항목으로 또 밀어 넣으면 목록에 같은 헤더가 두 번 뜬다.
|
|
79
|
+
*
|
|
80
|
+
* 아직 받지 않은 옵션은 라벨을 알 수 없다. 그래서 이 prop 을 쓰는 화면은
|
|
81
|
+
* `valueAsPrimitive` 를 켜지 않는 편이 안전하다 — 기본값(옵션 객체)이면 선택값이 라벨을
|
|
82
|
+
* 함께 들고 다녀서, 그 옵션이 목록에서 사라져도 트리거에 이름이 그대로 남는다.
|
|
83
|
+
*/
|
|
84
|
+
onReachEnd?: () => void;
|
|
85
|
+
/**
|
|
86
|
+
* 목록 끝에서 이만큼 행이 남았을 때 `onReachEnd` 를 부른다 — 스크롤이 바닥에 닿기 전에 미리 받아 둔다.
|
|
87
|
+
*
|
|
88
|
+
* **한 페이지 크기보다 충분히 작게 잡는다.** 한 페이지가 드롭다운을 채우고도 이 문턱만큼
|
|
89
|
+
* 남기지 못하면, 페이지가 도착하는 족족 다음 페이지를 다시 청하게 된다 — 사용자가 스크롤을
|
|
90
|
+
* 하지 않아도 목록 전체를 받아 오므로 페이징을 한 의미가 사라진다.
|
|
91
|
+
* (한 페이지 50개 · 드롭다운에 20행이 보인다면 남는 것은 30행이므로, 문턱은 그보다 작아야 한다)
|
|
92
|
+
*/
|
|
93
|
+
reachEndThreshold?: number;
|
|
94
|
+
/** 더 받아올 페이지가 남았는가. `false` 면 `onReachEnd` 를 더 부르지 않는다 */
|
|
95
|
+
hasMore?: boolean;
|
|
96
|
+
/** 다음 페이지를 받는 중 — 목록 하단에 로딩 표시를 내고, 그동안 `onReachEnd` 를 다시 부르지 않는다 */
|
|
97
|
+
loading?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* 검색을 서버로 넘긴다 — 내부 필터링을 하지 않고 `options` 를 받은 그대로 보여준다.
|
|
100
|
+
* `onSearchChange` 로 온 검색어에 맞는 목록을 소비 앱이 다시 내려줘야 한다.
|
|
101
|
+
*
|
|
102
|
+
* 켜면 검색바가 옵션 수와 무관하게 항상 나온다 — 검색 결과가 줄었다고 검색바가 사라지면
|
|
103
|
+
* 검색어를 지울 수단이 없어지기 때문이다.
|
|
104
|
+
*/
|
|
105
|
+
serverSearch?: boolean;
|
|
106
|
+
/** 검색어 변경. `serverSearch` 면 `searchDebounce` 만큼 묶어서 온다 */
|
|
107
|
+
onSearchChange?: (query: string) => void;
|
|
108
|
+
/** `serverSearch` 에서 검색어를 서버로 넘기기 전 기다리는 시간(ms) */
|
|
109
|
+
searchDebounce?: number;
|
|
66
110
|
label?: string;
|
|
67
111
|
labelWidth?: number | string;
|
|
68
112
|
/** 레이블 영역 아이콘 */
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 가변 행 높이 가상 스크롤의 계산부 — DOM 을 모르는 순수 자료구조다.
|
|
3
|
+
*
|
|
4
|
+
* 아직 그려지지 않은 행은 추정치로 두고, 화면에 나온 행은 실측으로 덮는다. 그래서
|
|
5
|
+
* "모든 행이 같은 높이"라는 가정 없이도 스크롤 위치 ↔ 행 인덱스를 오갈 수 있다 —
|
|
6
|
+
* depth 그룹 헤더처럼 리프와 높이가 다른 행이 섞여도 어긋나지 않는다.
|
|
7
|
+
* (Quasar QVirtualScroll 의 `virtual-scroll-item-size` 가 "추정치일 뿐"인 것과 같은 모델)
|
|
8
|
+
*
|
|
9
|
+
* 수천 행에서 렌더마다 새 배열을 만들면 그 자체가 비용이라, 제자리에서 고친다.
|
|
10
|
+
* 소유자는 ref 하나로 들고 있고, 화면에 반영할 필요가 있을 때만 리렌더를 건다.
|
|
11
|
+
*/
|
|
12
|
+
export interface RowMetrics {
|
|
13
|
+
/** 행별 높이. 실측 전에는 `estimate` 가 들어 있다 */
|
|
14
|
+
sizes: number[];
|
|
15
|
+
/** 실측을 마친 행인지 — 추정치를 평균에 섞지 않으려고 구분한다 */
|
|
16
|
+
measured: boolean[];
|
|
17
|
+
/** `offsets[i]` = 0..i-1 행 높이의 합. 길이는 `sizes.length + 1` 이라 마지막이 전체 높이다 */
|
|
18
|
+
offsets: number[];
|
|
19
|
+
/** 아직 안 그려진 행에 쓸 높이. 실측이 쌓일수록 그 평균으로 수렴한다 */
|
|
20
|
+
estimate: number;
|
|
21
|
+
/** 추정치 갱신용 누적 — 평균을 매번 다시 훑지 않으려고 합과 개수를 들고 있는다 */
|
|
22
|
+
measuredCount: number;
|
|
23
|
+
measuredTotal: number;
|
|
24
|
+
/** 이 인덱스부터 `offsets` 가 낡았다. `Infinity` 면 최신 */
|
|
25
|
+
dirtyFrom: number;
|
|
26
|
+
}
|
|
27
|
+
export declare function createRowMetrics(count: number, estimate: number): RowMetrics;
|
|
28
|
+
/**
|
|
29
|
+
* 목록 길이가 바뀌었을 때 표를 맞춘다.
|
|
30
|
+
*
|
|
31
|
+
* 늘어난 만큼은 추정치로 채우고 **앞쪽 실측은 그대로 둔다** — 무한 로딩은 뒤에 이어붙이는
|
|
32
|
+
* 것이라, 여기서 표를 새로 만들면 이미 잰 높이를 버리고 스크롤이 튄다. 줄어들 때는 잘라낸다
|
|
33
|
+
* (검색으로 목록이 좁아지는 경우인데, 그때는 같은 인덱스가 다른 행이므로 실측도 함께 버린다).
|
|
34
|
+
*/
|
|
35
|
+
export declare function resizeRowMetrics(metrics: RowMetrics, count: number): void;
|
|
36
|
+
/** 목록이 통째로 다른 것으로 갈렸을 때 — 실측을 전부 버리고 추정치만 남긴다 */
|
|
37
|
+
export declare function resetRowMetrics(metrics: RowMetrics, count: number): void;
|
|
38
|
+
/**
|
|
39
|
+
* 실측 높이를 반영한다. 값이 실제로 달라졌으면 `true`.
|
|
40
|
+
*
|
|
41
|
+
* 추정치도 실측 평균으로 함께 끌어당긴다 — 한 번도 안 그려진 뒤쪽 수천 행의 높이가
|
|
42
|
+
* 그만큼 사실에 가까워져, 스크롤바 길이와 "끝까지 내렸을 때"의 위치가 맞는다.
|
|
43
|
+
* 다만 1px 미만의 흔들림으로 표 전체를 다시 세우지는 않는다.
|
|
44
|
+
*/
|
|
45
|
+
export declare function setRowSize(metrics: RowMetrics, index: number, size: number): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* 낡은 구간의 누적 오프셋을 다시 센다. 이미 최신이면 아무 일도 하지 않는다.
|
|
48
|
+
* 바뀐 지점 앞은 그대로 두고 거기서부터만 이어 세므로, 아래쪽 행을 재도 전체를 훑지 않는다.
|
|
49
|
+
*/
|
|
50
|
+
export declare function rebuildOffsets(metrics: RowMetrics): void;
|
|
51
|
+
/** 목록 전체 높이 */
|
|
52
|
+
export declare function totalSize(metrics: RowMetrics): number;
|
|
53
|
+
/** `index` 번 행의 위쪽 끝 y */
|
|
54
|
+
export declare function offsetOf(metrics: RowMetrics, index: number): number;
|
|
55
|
+
export declare function sizeOf(metrics: RowMetrics, index: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* y 좌표에 놓인 행의 인덱스 (이진 탐색). 목록 끝을 넘으면 마지막 행을 준다.
|
|
58
|
+
* 수천 행에서 스크롤마다 훑으면 그게 곧 렉이라 선형 탐색을 쓰지 않는다.
|
|
59
|
+
*/
|
|
60
|
+
export declare function indexAtOffset(metrics: RowMetrics, y: number): number;
|
|
@@ -29,3 +29,18 @@ export declare function collectGroupLeafValues(flat: FlatOption[], groupIndex: n
|
|
|
29
29
|
export declare const isHtmlLabel: (label: string) => boolean;
|
|
30
30
|
/** HTML 라벨에서 태그를 제거한 텍스트 (검색 매칭용, 원본 extractText) */
|
|
31
31
|
export declare const extractText: (html: string) => string;
|
|
32
|
+
/**
|
|
33
|
+
* 아직 한 번도 그려지지 않은 행의 **추정** 높이(px). 리프 옵션은 세로 패딩 4px + 행간 20px
|
|
34
|
+
* 이라 보통 이 값이지만, 그룹 헤더나 큰 글씨가 섞인 라벨은 다르다 — 화면에 나온 행은
|
|
35
|
+
* 실측으로 덮이므로(`row-metrics.ts`) 이 값은 처음 스크롤바 길이를 잡는 출발점일 뿐이다.
|
|
36
|
+
*/
|
|
37
|
+
export declare const OPTION_ROW_HEIGHT = 28;
|
|
38
|
+
/**
|
|
39
|
+
* 화면 위·아래로 더 그려둘 기본 여유 행 수.
|
|
40
|
+
* 640px 드롭다운이 20행 남짓 보이므로, 앞뒤 10행이면 한 화면을 굴리는 동안 빈 칸이 보이지 않는다.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DEFAULT_VIRTUAL_BUFFER = 10;
|
|
43
|
+
/** 목록 끝에서 이만큼 행이 남았을 때 다음 페이지를 청하는 기본값 */
|
|
44
|
+
export declare const DEFAULT_REACH_END_THRESHOLD = 10;
|
|
45
|
+
/** `serverSearch` 에서 검색어를 서버로 넘기기 전 기다리는 기본 시간(ms) */
|
|
46
|
+
export declare const DEFAULT_SEARCH_DEBOUNCE = 300;
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
| Prop | Type | Default | Description |
|
|
10
10
|
|------|------|---------|-------------|
|
|
11
11
|
| `value?` | `string` | — | 값 (제어) |
|
|
12
|
-
| `
|
|
12
|
+
| `size?` | `SFieldSize` | `'sm'` | 크기 — `SInput` 등 다른 필드와 같은 등급이다. 글자 크기·행간·안쪽 여백·모서리가 함께 바뀐다. 한 줄 필드와 나란히 놓이는 자리라면 같은 등급으로 맞춘다. |
|
|
13
|
+
| `rows?` | `number` | `MIN_ROWS` | 행 수 — 기본 2줄이고, 그보다 크게 주면 그만큼 높아진다. 줄여도 `size` 가 정한 최소 높이(2줄) 아래로는 내려가지 않는다. |
|
|
14
|
+
| `autogrow?` | `boolean` | `false` | 입력 내용에 맞춰 높이가 늘어난다 — 스크롤 대신 필드가 자란다. 켜면 모서리를 끌어 크기를 바꾸는 손잡이가 사라진다. 사용자가 늘려 둔 높이를 다음 타이핑이 도로 계산해 버려, 둘을 함께 두면 끌어도 제자리로 돌아가는 것처럼 보이기 때문이다. **상한을 정하려면 `maxRows` 를 함께 준다.** 상한이 없으면 긴 글에서 필드가 끝없이 자라 모달·드로어에서는 아래쪽 버튼을 화면 밖으로 밀어낸다. |
|
|
15
|
+
| `maxRows?` | `number` | — | `autogrow` 의 상한(줄 수). 여기 닿으면 더 자라지 않고 그 안에서 스크롤한다. `autogrow` 가 꺼져 있으면 아무 일도 하지 않는다. |
|
|
13
16
|
| `rules?` | `Rule[]` | — | 유효성 규칙 — blur 시 자동 검증 |
|
|
14
17
|
| `status?` | `SFieldStatus` | — | 필드 상태 ('default' | 'pass' | 'error') |
|
|
15
18
|
| `focused?` | `boolean` | — | 포커스 상태를 밖에서 지정한다 — 강조 테두리·링이 즉시 걸린다 (SField 로 그대로 넘어간다) |
|
|
@@ -44,6 +47,7 @@
|
|
|
44
47
|
|
|
45
48
|
### Used by
|
|
46
49
|
|
|
50
|
+
- [SChatInput](../SChatInput)
|
|
47
51
|
- [SKeyValueTable](../SKeyValueTable)
|
|
48
52
|
|
|
49
53
|
### Depends on
|
|
@@ -55,6 +59,7 @@
|
|
|
55
59
|
```mermaid
|
|
56
60
|
graph TD;
|
|
57
61
|
STextarea --> SField
|
|
62
|
+
SChatInput --> STextarea
|
|
58
63
|
SKeyValueTable --> STextarea
|
|
59
64
|
style STextarea fill:#f9f,stroke:#333,stroke-width:4px
|
|
60
65
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type TextareaHTMLAttributes, type CSSProperties } from 'react';
|
|
2
|
-
import { type SFieldAddonAlign, type SFieldStatus } from '../SField';
|
|
2
|
+
import { type SFieldAddonAlign, type SFieldSize, type SFieldStatus } from '../SField';
|
|
3
3
|
import { type SIconName } from '../SIcon';
|
|
4
4
|
import { type SColor } from '../../lib/color';
|
|
5
5
|
import { type Rule } from '../../lib/form';
|
|
@@ -12,8 +12,31 @@ export interface STextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextArea
|
|
|
12
12
|
onValueChange?: (value: string) => void;
|
|
13
13
|
/** 네이티브 onChange (form-agnostic) */
|
|
14
14
|
onChange?: TextareaHTMLAttributes<HTMLTextAreaElement>['onChange'];
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* 크기 — `SInput` 등 다른 필드와 같은 등급이다. 글자 크기·행간·안쪽 여백·모서리가 함께 바뀐다.
|
|
17
|
+
* 한 줄 필드와 나란히 놓이는 자리라면 같은 등급으로 맞춘다.
|
|
18
|
+
*/
|
|
19
|
+
size?: SFieldSize;
|
|
20
|
+
/**
|
|
21
|
+
* 행 수 — 기본 2줄이고, 그보다 크게 주면 그만큼 높아진다.
|
|
22
|
+
* 줄여도 `size` 가 정한 최소 높이(2줄) 아래로는 내려가지 않는다.
|
|
23
|
+
*/
|
|
16
24
|
rows?: number;
|
|
25
|
+
/**
|
|
26
|
+
* 입력 내용에 맞춰 높이가 늘어난다 — 스크롤 대신 필드가 자란다.
|
|
27
|
+
*
|
|
28
|
+
* 켜면 모서리를 끌어 크기를 바꾸는 손잡이가 사라진다. 사용자가 늘려 둔 높이를 다음 타이핑이
|
|
29
|
+
* 도로 계산해 버려, 둘을 함께 두면 끌어도 제자리로 돌아가는 것처럼 보이기 때문이다.
|
|
30
|
+
*
|
|
31
|
+
* **상한을 정하려면 `maxRows` 를 함께 준다.** 상한이 없으면 긴 글에서 필드가 끝없이 자라
|
|
32
|
+
* 모달·드로어에서는 아래쪽 버튼을 화면 밖으로 밀어낸다.
|
|
33
|
+
*/
|
|
34
|
+
autogrow?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* `autogrow` 의 상한(줄 수). 여기 닿으면 더 자라지 않고 그 안에서 스크롤한다.
|
|
37
|
+
* `autogrow` 가 꺼져 있으면 아무 일도 하지 않는다.
|
|
38
|
+
*/
|
|
39
|
+
maxRows?: number;
|
|
17
40
|
/** 유효성 규칙 — blur 시 자동 검증 */
|
|
18
41
|
rules?: Rule[];
|
|
19
42
|
/** 필드 상태 ('default' | 'pass' | 'error') */
|