@simplysm/sd-claude 14.0.76 → 14.0.77
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/claude/output-styles/sd-tone.md +128 -0
- package/claude/references/sd-simplysm14/apis/angular/README.md +28 -89
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +75 -32
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +65 -29
- package/claude/references/sd-simplysm14/apis/angular/crud.md +86 -21
- package/claude/references/sd-simplysm14/apis/angular/forms.md +168 -42
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +200 -49
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +64 -20
- package/claude/references/sd-simplysm14/apis/angular/layout.md +75 -30
- package/claude/references/sd-simplysm14/apis/angular/modal.md +92 -40
- package/claude/references/sd-simplysm14/apis/angular/routing.md +86 -25
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +72 -41
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +113 -21
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +108 -33
- package/claude/references/sd-simplysm14/apis/angular/toast.md +81 -30
- package/claude/references/sd-simplysm14/apis/angular/visual.md +140 -32
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +46 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +59 -48
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +17 -7
- package/claude/references/sd-simplysm14/apis/core-common/README.md +43 -116
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +74 -109
- package/claude/references/sd-simplysm14/apis/core-common/features.md +40 -35
- package/claude/references/sd-simplysm14/apis/core-common/types.md +80 -106
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +142 -111
- package/claude/references/sd-simplysm14/apis/core-node/README.md +7 -16
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +33 -38
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +25 -33
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +27 -38
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +32 -60
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -45
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +35 -81
- package/claude/references/sd-simplysm14/apis/excel/README.md +178 -80
- package/claude/references/sd-simplysm14/apis/lint/README.md +5 -0
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +28 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-client/README.md +57 -50
- package/claude/references/sd-simplysm14/apis/service-server/README.md +8 -15
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +24 -16
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +55 -31
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +28 -44
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +59 -18
- package/claude/references/sd-simplysm14/apis/service-server/server.md +37 -46
- package/claude/references/sd-simplysm14/manuals/client-component.md +3 -1
- package/claude/references/sd-simplysm14/manuals/logging.md +9 -8
- package/claude/rules/sd-base-rules.md +380 -219
- package/claude/settings.json +1 -0
- package/claude/skills/sd-commit/SKILL.md +31 -8
- package/claude/skills/sd-docs/SKILL.md +15 -10
- package/claude/skills/sd-docs/references/subagent-prompt.md +26 -8
- package/claude/skills/sd-impl/SKILL.md +1 -1
- package/claude/skills/sd-skill/references/skill-authoring.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +22 -13
- package/claude/skills/sd-spec/references/spec-authoring.md +1 -1
- package/claude/skills/sd-unpack/SKILL.md +150 -26
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/_common.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/eml_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/pdf_handler.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/_common.py +17 -2
- package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +100 -24
- package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +140 -27
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +698 -107
- package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +34 -26
- package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +130 -8
- package/package.json +1 -1
|
@@ -1,42 +1,134 @@
|
|
|
1
1
|
# @simplysm/angular — shared-data
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
서버 마스터데이터(부서·거래처·코드 등)를 키 기반으로 등록/구독. 서버 변경 이벤트로 자동 부분 갱신.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## SdSharedDataProvider<T> (abstract, 사용자가 상속해 `initialize()` 안에서 `register` 호출)
|
|
6
6
|
|
|
7
|
-
```
|
|
7
|
+
```ts
|
|
8
|
+
abstract class SdSharedDataProvider<T extends Record<string, SharedDataBase<string|number>>> {
|
|
9
|
+
loadingCount: WritableSignal<number>;
|
|
10
|
+
abstract initialize(): void;
|
|
11
|
+
register<K extends keyof T & string>(name: K, info: SharedDataInfo<T[K]>): void;
|
|
12
|
+
getHandle<K extends keyof T & string>(name: K): SharedDataHandle<T[K]>;
|
|
13
|
+
emitAsync<K extends keyof T & string>(name: K, changeKeys?: (string|number)[]): Promise<void>;
|
|
14
|
+
wait(): Promise<void>; // loadingCount 가 0 될 때까지
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface SharedDataBase<TKey> {
|
|
18
|
+
__valueKey: TKey;
|
|
19
|
+
__searchText: string;
|
|
20
|
+
__isHidden: boolean;
|
|
21
|
+
__parentKey?: TKey;
|
|
22
|
+
}
|
|
23
|
+
interface SharedDataInfo<T> {
|
|
24
|
+
serviceKey: string; // SdServiceClientFactoryProvider 의 client key
|
|
25
|
+
getter: (changeKeys?: (string|number)[]) => Promise<T[]>;
|
|
26
|
+
filter?: unknown;
|
|
27
|
+
orderBy?: (item: T) => any;
|
|
28
|
+
}
|
|
29
|
+
interface SharedDataHandle<T> {
|
|
30
|
+
items: Signal<T[]>;
|
|
31
|
+
get(key: T["__valueKey"]|undefined): T|undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const SdSharedDataChangeEvent = defineEvent<{ name: string; filter: unknown }, (string|number)[]|undefined>("SdSharedDataChange");
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `register` — 데이터 소스 등록. `getHandle` 첫 호출 시 `getter()` lazy 로드 + 서버 이벤트 리스너 등록. 이후 `SdSharedDataChangeEvent` 수신 시 `changeKeys` 기준 부분 갱신(또는 undefined 면 전체 reload).
|
|
38
|
+
- `getHandle.items` — readonly signal. orderBy 적용된 정렬 상태.
|
|
39
|
+
- `getHandle.get(key)` — `__valueKey` 로 O(1) 조회.
|
|
40
|
+
- `emitAsync` — 클라이언트에서 변경 발생 시 같은 `serviceKey` 의 다른 클라이언트에 변경 통지(filter 동일한 등록만 수신).
|
|
41
|
+
- `wait` — 초기 로드/갱신이 완료될 때까지. CRUD 컨테이너의 ready 처리에 사용.
|
|
42
|
+
- `SharedDataBase` 의 `__searchText` — `matchesSearchText` 가 사용할 검색 대상 문자열. `__isHidden` — 보이지 않을 항목 마킹. `__parentKey` — 트리형 데이터의 부모 키.
|
|
43
|
+
- `filter` — 서버 측 필터 식별자. 다른 filter 로 등록된 같은 name 은 별개 인스턴스.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
8
46
|
@Injectable({ providedIn: "root" })
|
|
9
|
-
class MySharedData extends SdSharedDataProvider<{ depts:
|
|
10
|
-
initialize()
|
|
47
|
+
class MySharedData extends SdSharedDataProvider<{ depts: Dept }> {
|
|
48
|
+
initialize() {
|
|
11
49
|
this.register("depts", {
|
|
12
50
|
serviceKey: "main",
|
|
13
|
-
getter: (
|
|
14
|
-
orderBy: (
|
|
51
|
+
getter: async (keys) => await api.depts.list(keys),
|
|
52
|
+
orderBy: (d) => d.name,
|
|
15
53
|
});
|
|
16
54
|
}
|
|
17
55
|
}
|
|
56
|
+
const depts = mySharedData.getHandle("depts").items();
|
|
18
57
|
```
|
|
19
58
|
|
|
20
|
-
|
|
21
|
-
- `register(name, info)` 후 `getHandle(name)` → `SharedDataHandle<T> { items: Signal<T[]>; get(key) }`. 첫 호출 시 lazy load + 이벤트 리스너 등록.
|
|
22
|
-
- `emitAsync(name, changeKeys?)` → 다른 클라이언트(또는 자기 자신)에 `SdSharedDataChangeEvent` 발행. `changeKeys` 없으면 전체 리로드, 있으면 해당 키들만 재조회 후 merge (orderBy 재적용).
|
|
23
|
-
- `loadingCount = signal(0)`, `wait()` (loadingCount 0까지).
|
|
24
|
-
- `SdSharedDataChangeEvent` = `defineEvent<{ name; filter }, (string|number)[] | undefined>("SdSharedDataChange")` — 동일 name+filter 매칭 리스너에 키 발행.
|
|
59
|
+
## SdSharedDataSelect — `<sd-shared-data-select>`
|
|
25
60
|
|
|
26
|
-
|
|
61
|
+
```ts
|
|
62
|
+
class SdSharedDataSelect<TMode, TModal, TItem extends SharedDataBase<...>>
|
|
63
|
+
value = model<SelectModeValue<TItem["__valueKey"]|undefined>[TMode]>();
|
|
64
|
+
items = input.required<TItem[]>();
|
|
65
|
+
disabled/required/useUndefined/inset/inline = input(false); size = input<"sm"|"lg">();
|
|
66
|
+
selectMode = input("single" as TMode);
|
|
67
|
+
filterFn = input<(item, index, ...params) => boolean>();
|
|
68
|
+
filterFnParams = input<any[]>();
|
|
69
|
+
modal = input<SdSelectModalInfo<TModal>>();
|
|
70
|
+
editModal = input<SdModalInfo<SdModalContentDef<boolean>>>();
|
|
71
|
+
selectClass = input<string>();
|
|
72
|
+
multiSelectionDisplayDirection = input<"vertical">();
|
|
73
|
+
getIsHiddenFn = input<(item, index) => boolean>(...); // 기본 (i)=>i.__isHidden
|
|
74
|
+
getSearchTextFn = input<(item, index) => string>(...); // 기본 (i)=>i.__searchText
|
|
75
|
+
displayOrderKeyProp = input<string>();
|
|
76
|
+
```
|
|
27
77
|
|
|
28
|
-
|
|
78
|
+
- 공유데이터 전용 셀렉트. `items` 는 보통 `sharedData.getHandle("xx").items()`.
|
|
79
|
+
- `useUndefined` — true 면 "선택 안 함" 옵션 노출. 단일 모드에서 null 가능.
|
|
80
|
+
- `filterFn` + `filterFnParams` — 추가 필터(signal 변경 시 재계산).
|
|
81
|
+
- `modal` — "더보기" 검색 모달. 미지정 시 모달 버튼 안 보임.
|
|
82
|
+
- `editModal` — 항목 편집 모달(연필 아이콘). true emit 시 데이터 reload.
|
|
83
|
+
- `getIsHiddenFn`/`getSearchTextFn` — 기본은 `SharedDataBase` 의 `__isHidden`/`__searchText` 사용. 커스텀 가능.
|
|
84
|
+
- `displayOrderKeyProp` — 트리 표시 시 정렬에 쓸 prop 이름.
|
|
29
85
|
|
|
30
|
-
|
|
86
|
+
## SdSharedDataSelectButton — `<sd-shared-data-select-button>`
|
|
31
87
|
|
|
32
|
-
|
|
88
|
+
```ts
|
|
89
|
+
value = model<SelectModeValue<string|number>[TMode]>();
|
|
90
|
+
items = input<TItem[]>([]);
|
|
91
|
+
modal = input.required<SdSelectModalInfo<TModal>>();
|
|
92
|
+
selectMode = input<TMode>("single" as TMode);
|
|
93
|
+
disabled/required/inset = input(false); size = input<"sm"|"lg">();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- 셀렉트 드롭다운 대신 항상 모달로 검색. `<ng-content>` 가 선택값 표시 슬롯. `modal` 필수.
|
|
97
|
+
|
|
98
|
+
## SdSharedDataSelectList — `<sd-shared-data-select-list>`
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
class SdSharedDataSelectList<TItem extends SharedDataBase<...>, TModal>
|
|
102
|
+
selectedItem = model<TItem>();
|
|
103
|
+
canChangeFn = input<(item: TItem|undefined) => boolean|Promise<boolean>>(...);
|
|
104
|
+
items = input.required<TItem[]>();
|
|
105
|
+
selectedIcon = input<string>();
|
|
106
|
+
useUndefined = input(false);
|
|
107
|
+
filterFn = input<(item, index) => boolean>();
|
|
108
|
+
modal = input<SdSelectModalInfo<TModal>>();
|
|
109
|
+
header = input<string>();
|
|
110
|
+
pageItemCount = input<number>();
|
|
111
|
+
```
|
|
33
112
|
|
|
34
|
-
|
|
113
|
+
- 사이드 패널형 리스트(단일 선택). 검색 박스 + 페이지네이션 자동.
|
|
114
|
+
- `canChangeFn` — 변경 직전 비동기 확인.
|
|
115
|
+
- `pageItemCount` — 페이지당 항목 수. 미지정 시 페이지 분할 없음.
|
|
35
116
|
|
|
36
|
-
##
|
|
117
|
+
## matchesSearchText
|
|
37
118
|
|
|
38
|
-
|
|
119
|
+
```ts
|
|
120
|
+
function matchesSearchText(itemText: string, searchQuery: string|undefined): boolean
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- 공백 분리 AND 검색. 모든 단어가 `itemText` (대소문자 무시) 안에 포함되면 true. 빈 query 는 true.
|
|
124
|
+
- 커스텀 선택 리스트에서 검색 필터 짤 때 사용.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
items.filter((it) => matchesSearchText(it.name + " " + it.code, q()))
|
|
128
|
+
```
|
|
39
129
|
|
|
40
|
-
##
|
|
130
|
+
## 주의
|
|
41
131
|
|
|
42
|
-
|
|
132
|
+
- `SdSharedDataProvider` 상속 후 `initialize()` 안에서만 `register`. 부트스트랩 시 1회 호출.
|
|
133
|
+
- 같은 name 으로 다시 `register` 호출 시 generation 증가 + listener 교체 → 이전 비동기 결과는 무시.
|
|
134
|
+
- 변경 이벤트는 같은 `serviceKey` 의 같은 `name`·동일 `filter` 등록만 수신.
|
|
@@ -1,52 +1,127 @@
|
|
|
1
1
|
# @simplysm/angular — sheet
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
데이터 그리드. 컬럼·셀 템플릿·정렬·페이징·선택·확장 트리·컬럼 설정 모달 내장.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## SdSheet — `<sd-sheet>`
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
class SdSheet<TItem>
|
|
9
|
+
key = input<string>();
|
|
10
|
+
items = input<TItem[]>([]);
|
|
11
|
+
trackByFn = input<(item: TItem, index: number) => unknown>((i) => i);
|
|
12
|
+
selectMode = input<"single"|"multi">();
|
|
13
|
+
autoSelect = input<"click"|"focus">();
|
|
14
|
+
getItemSelectableFn = input<(item) => boolean|string>();
|
|
15
|
+
getChildrenFn = input<(item, index) => TItem[]|undefined>();
|
|
16
|
+
useAutoSort = input(false);
|
|
17
|
+
visiblePageCount = input(10);
|
|
18
|
+
totalPageCount = input(0);
|
|
19
|
+
itemsPerPage = input(0);
|
|
20
|
+
focusMode = input<"row"|"cell">("cell");
|
|
21
|
+
inset = input(false);
|
|
22
|
+
contentStyle = input<string>();
|
|
23
|
+
getItemCellClassFn = input<(item, colKey: string) => string>();
|
|
24
|
+
getItemCellStyleFn = input<(item, colKey: string) => string|undefined>();
|
|
25
|
+
hideConfigBar = input(false);
|
|
26
|
+
|
|
27
|
+
itemKeydown = output<SdSheetItemKeydownEventParam<TItem>>();
|
|
28
|
+
cellKeydown = output<SdSheetCellKeydownEventParam<TItem>>();
|
|
29
|
+
|
|
30
|
+
selectedKeys = model<unknown[]>([]);
|
|
31
|
+
expandedItems = model<TItem[]>([]);
|
|
32
|
+
sorts = model<SortingDef[]>([]);
|
|
33
|
+
currentPage = model(0);
|
|
34
|
+
|
|
35
|
+
columnControlsInput = input<readonly SdSheetColumn[]>([]); // 동적 컬럼 주입용
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `key` — 지정 시 `SdSystemConfigProvider` 키 `sd-sheet.<key>` 로 컬럼 width/hidden/fixed/ordering 자동 저장·복원. 미지정이면 세션 한정.
|
|
39
|
+
- `items` + `trackByFn` — 데이터와 키 추출. 트리는 `getChildrenFn` 으로 자식 반환(`expandedItems` 양방향 model 로 펼침 상태).
|
|
40
|
+
- `selectMode` — `single`/`multi`. 미지정이면 선택 안 함. `selectedKeys` 는 `trackByFn` 반환값 배열.
|
|
41
|
+
- `autoSelect` — `click`: 행 클릭 시 선택, `focus`: 포커스만 들어가도 선택. 미지정이면 명시적 체크박스만.
|
|
42
|
+
- `getItemSelectableFn` — true 면 선택 가능, false/string 이면 불가(string 은 사유 툴팁).
|
|
43
|
+
- `useAutoSort` — true 면 `sorts` 변경 시 클라이언트 자체 정렬. false 면 서버 사이드 페치 가정.
|
|
44
|
+
- `totalPageCount`/`itemsPerPage`/`visiblePageCount`/`currentPage` — 페이지네이션. `totalPageCount=0` 이면 페이지바 숨김.
|
|
45
|
+
- `focusMode` — `row` 면 행 단위 포커스, `cell` 면 셀 단위(엑셀형).
|
|
46
|
+
- `inset` — 컨테이너 안에 박힌 룩(보더 제거).
|
|
47
|
+
- `getItemCellClassFn`/`getItemCellStyleFn` — 셀별 동적 class/style.
|
|
48
|
+
- `hideConfigBar` — 상단 컬럼 설정 바(컬럼 표시/순서 조작) 숨김.
|
|
49
|
+
- `itemKeydown`/`cellKeydown` — 단축키 처리. focusMode 에 따라 둘 중 1개 활용.
|
|
50
|
+
- 자식: `<sd-sheet-column>` 들을 content projection 으로 배치.
|
|
6
51
|
|
|
7
52
|
```html
|
|
8
|
-
<sd-sheet
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
[selectMode]="'multi'"
|
|
13
|
-
[(selectedKeys)]="selectedKeys"
|
|
14
|
-
[(sorts)]="sorts"
|
|
15
|
-
[(currentPage)]="page"
|
|
16
|
-
[totalPageCount]="totalPages"
|
|
17
|
-
[itemsPerPage]="50"
|
|
18
|
-
[useAutoSort]="false">
|
|
19
|
-
|
|
20
|
-
<sd-sheet-column [key]="'no'" [header]="'번호'" [width]="'80px'" [fixed]="true">
|
|
21
|
-
<ng-template cell let-item="item" let-index="index">{{ index + 1 }}</ng-template>
|
|
53
|
+
<sd-sheet [items]="rows()" [trackByFn]="trackById" [(selectedKeys)]="sel" selectMode="multi" key="invoice-list">
|
|
54
|
+
<sd-sheet-column key="no" header="번호" width="80px" />
|
|
55
|
+
<sd-sheet-column key="name" header="이름">
|
|
56
|
+
<ng-template cell [cell]="rows()" let-item>{{ item.name }}</ng-template>
|
|
22
57
|
</sd-sheet-column>
|
|
23
58
|
</sd-sheet>
|
|
24
59
|
```
|
|
25
60
|
|
|
26
|
-
## `<sd-sheet
|
|
61
|
+
## SdSheetColumn — `<sd-sheet-column>` (Directive)
|
|
27
62
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
63
|
+
```ts
|
|
64
|
+
class SdSheetColumn<T = unknown>
|
|
65
|
+
key = input.required<string>();
|
|
66
|
+
header = input<string|string[]>(""); // 배열이면 다단 헤더
|
|
67
|
+
headerStyle = input<string>();
|
|
68
|
+
tooltip = input<string>();
|
|
69
|
+
width = input<string>(); // CSS 값 ("120px"·"1fr")
|
|
70
|
+
fixed = input(false); // 좌측 고정 컬럼
|
|
71
|
+
hidden = input(false);
|
|
72
|
+
collapse = input(false); // 접힘(헤더만 좁게)
|
|
73
|
+
disableSorting = input(false);
|
|
74
|
+
disableResizing = input(false);
|
|
75
|
+
ordering = input(0); // 표시 순서 weight
|
|
32
76
|
|
|
33
|
-
|
|
77
|
+
interface SdSheetCellContext<T = unknown> { ... } // 셀 템플릿 컨텍스트
|
|
78
|
+
```
|
|
34
79
|
|
|
35
|
-
|
|
80
|
+
- `key` — 정렬·설정 저장 식별자. 시트 내 unique.
|
|
81
|
+
- `header` 배열 — `["상위", "하위"]` 형태로 2단·3단 헤더 그룹화. 인접 컬럼이 같은 상위 헤더면 머지.
|
|
82
|
+
- `fixed` — 좌측 sticky.
|
|
83
|
+
- `ordering` — 사용자가 드래그로 바꾼 순서가 우선. 같은 ordering 끼리는 선언 순서.
|
|
36
84
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
85
|
+
## SdSheetColumnCellTemplate — `<ng-template cell>` (Directive)
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
class SdSheetColumnCellTemplate<T> { cell = input.required<T[]>(); }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- `<sd-sheet-column>` 안의 셀 템플릿 마커. `[cell]` 에 items 배열 바인딩(type guard 용도). let-item, let-index, let-depth 사용 가능.
|
|
92
|
+
|
|
93
|
+
## SdSheetConfigModal — `<sd-sheet-config-modal>` (SdModalContentDef)
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
sheetKey = input.required<string>();
|
|
97
|
+
controls = input.required<readonly SdSheetColumn[]>();
|
|
98
|
+
config = input.required<SdSheetConfig|undefined>();
|
|
99
|
+
close = output<SdSheetConfig|undefined>();
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- 컬럼 표시/숨김/순서/너비 설정 모달. `SdSheet` 내부에서 호출. 직접 부를 일은 거의 없음.
|
|
41
103
|
|
|
42
104
|
## 타입
|
|
43
105
|
|
|
44
|
-
```
|
|
45
|
-
interface SdSheetColumnDef {
|
|
46
|
-
|
|
47
|
-
|
|
106
|
+
```ts
|
|
107
|
+
interface SdSheetColumnDef {
|
|
108
|
+
key, header, headerStyle, tooltip, width, fixed, hidden, collapse,
|
|
109
|
+
disableSorting, disableResizing, ordering
|
|
110
|
+
}
|
|
111
|
+
interface SdSheetHeaderDef {
|
|
112
|
+
text, colspan, rowspan, isLastRow, fixed, colDef, colIndex
|
|
113
|
+
}
|
|
114
|
+
interface SdSheetConfig {
|
|
115
|
+
columnRecord: Record<string, { width?, hidden?, fixed?, ordering? }>;
|
|
116
|
+
}
|
|
117
|
+
interface SdSheetItemKeydownEventParam<T> { item: T; event: KeyboardEvent; }
|
|
118
|
+
interface SdSheetCellKeydownEventParam<T> { item: T; key: string; event: KeyboardEvent; }
|
|
48
119
|
```
|
|
49
120
|
|
|
50
|
-
|
|
121
|
+
- `SdSheetCellContext<T>` 는 셀 템플릿 안에서 노출되는 context 타입(item/index/depth/edit mode 등).
|
|
122
|
+
|
|
123
|
+
## 주의
|
|
51
124
|
|
|
52
|
-
|
|
125
|
+
- `key` 지정 시 `SdSystemConfigProvider` 가 부착되어 있어야 영구 저장. 미부착이면 `SdLocalStorageProvider` 경유.
|
|
126
|
+
- `selectMode=multi` 일 때 `selectedKeys` 는 `trackByFn` 반환 키. `items` 와 별개 배열.
|
|
127
|
+
- 트리(`getChildrenFn`) + 정렬(`useAutoSort=true`) 동시 사용 시 정렬은 각 depth 안에서만 적용.
|
|
@@ -1,46 +1,97 @@
|
|
|
1
|
-
# @simplysm/angular — toast
|
|
1
|
+
# @simplysm/angular — toast / busy / print
|
|
2
2
|
|
|
3
|
-
전역
|
|
3
|
+
전역 알림·로딩·인쇄 프로바이더. 컨테이너는 첫 호출 시 body 에 자동 생성.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## SdToastProvider (root)
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
toast.warning("...");
|
|
12
|
-
toast.danger("...");
|
|
7
|
+
```ts
|
|
8
|
+
alertThemes: WritableSignal<SdToastSeverity[]>; // 여기에 포함된 severity 는 window.alert 로 강제
|
|
9
|
+
overlap: WritableSignal<boolean>; // true 면 동시 표시 안 함(새 토스트가 기존 제거)
|
|
10
|
+
beforeShowFn?: (theme: SdToastSeverity) => void;
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
info/success/warning/danger(message: string, useProgress?: false): void;
|
|
13
|
+
info/success/warning/danger(message: string, useProgress: true): WritableSignal<number>;
|
|
14
|
+
notify<T extends SdToastContentDef<O>>(input: SdToastInput<T>): Promise<O|undefined>;
|
|
15
|
+
try<R>(fn: () => Promise<R>|R, messageFn?: (err) => string): Promise<R|undefined>|R|undefined;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
type SdToastSeverity = "info"|"success"|"warning"|"danger";
|
|
18
|
+
type SdToastTheme = "primary"|"secondary"|SdToastSeverity|"gray"|"blue-gray";
|
|
19
|
+
interface SdToastContentDef<O> { close: OutputEmitterRef<O|undefined>; }
|
|
20
|
+
interface SdToastInput<T> { type: Type<T>; inputs: <T 의 input prop 들, close 제외>; }
|
|
19
21
|
```
|
|
20
22
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
- `alertThemes
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
23
|
+
- `info`/`success` 는 `polite` aria-live, `warning`/`danger` 는 `assertive`/`alert` role.
|
|
24
|
+
- `useProgress=true` 면 진행률 토스트. 반환 signal 에 0~100 set. 100 도달 후 1초 뒤 자동 해제. progress 모드가 아니면 3초(호버 중이면 마우스 떠난 뒤 1초) 자동 해제.
|
|
25
|
+
- `alertThemes` 에 severity 포함되면 토스트 대신 `window.alert(message)`. 키오스크/PWA 백그라운드 알림 강제용.
|
|
26
|
+
- `beforeShowFn` — 매 토스트 표시 직전 호출(소리·진동 등 부수효과).
|
|
27
|
+
- `notify` — 커스텀 컴포넌트 컨텐츠로 토스트. 컴포넌트가 `close.emit(result)` 호출 시 Promise resolve, 5초 후 자동 dismiss(undefined resolve).
|
|
28
|
+
- `try` — fn 실행 후 throw 된 Error 의 메시지로 `danger` 토스트 + `SdSystemLogProvider.writeAsync('error', ...)` 호출. 비-Error throw 는 다시 던짐.
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
```ts
|
|
31
|
+
sdToast.success("저장 완료");
|
|
32
|
+
const sig = sdToast.info("업로드 중...", true); sig.set(50);
|
|
33
|
+
await sdToast.try(async () => await api.save(item));
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## SdToast / SdToastContainer
|
|
37
|
+
|
|
38
|
+
내부 사용 컴포넌트. 직접 쓸 일 거의 없음. `SdToastProvider` 가 첫 호출 시 `<sd-toast-container>` 를 body 에 append.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// SdToastContainer
|
|
42
|
+
overlap = input(false); // true 면 절대배치로 1개만 표시되는 룩
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## SdBusyProvider (root)
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
type: WritableSignal<SdBusyType>; // "spinner"|"bar"|"cube", default "bar"
|
|
49
|
+
globalBusyCount: WritableSignal<number>; // >0 이면 전역 busy 표시. provideSdAngular 가 navigation 동안 증감
|
|
50
|
+
type SdBusyType = "spinner"|"bar"|"cube";
|
|
51
|
+
```
|
|
28
52
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
interface SdToastInput<T> { type: Type<T>; inputs: DirectiveInputSignals<T> 제외 close }
|
|
53
|
+
- `globalBusyCount` 증가/감소로 전역 잠금 화면 토글.
|
|
54
|
+
- `type` — 인디케이터 모양. `spinner` 는 원형 회전, `bar` 는 상단 진행 바(슬림), `cube` 는 4분할 큐브 애니메이션.
|
|
32
55
|
|
|
33
|
-
|
|
56
|
+
## SdBusyContainer — `<sd-busy-container>`
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
busy = input(false); message = input<string|undefined>();
|
|
60
|
+
type = input<SdBusyType|undefined>(); // 미지정이면 SdBusyProvider.type() 사용
|
|
61
|
+
progressPercent = input<number|undefined>(); // 0~100, null 이면 막대 숨김
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- 일부 영역만 busy 표시. `busy` true 동안 자식 영역에 오버레이 + 키보드 입력 차단.
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<sd-busy-container [busy]="loading()" [progressPercent]="pct()">...영역 내용...</sd-busy-container>
|
|
34
68
|
```
|
|
35
69
|
|
|
36
|
-
|
|
70
|
+
## SdPrintProvider (root)
|
|
37
71
|
|
|
38
|
-
|
|
72
|
+
```ts
|
|
73
|
+
printAsync<T extends SdPrint>(template: SdPrintInput<T>, options?: { size?: string; margin?: string }): Promise<void>;
|
|
74
|
+
getPdfBufferAsync<T extends SdPrint>(template: SdPrintInput<T>, options?: { orientation?: "portrait"|"landscape"; pageSize?: string }): Promise<Uint8Array>;
|
|
39
75
|
|
|
40
|
-
|
|
41
|
-
|
|
76
|
+
interface SdPrint { initialized: Signal<boolean>; readonly _optionalPrintInputs?: string; }
|
|
77
|
+
interface SdPrintInput<T, X = ""> { type: Type<T>; inputs: <T 의 input prop 들>; }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- 인쇄용 컴포넌트를 동적으로 body 에 부착 → `initialized() === true` 대기 → 이미지 로드 완료 대기 → `window.print()` 또는 jsPDF + html-to-image 로 PDF 버퍼 생성.
|
|
81
|
+
- `printAsync.options.size` — `@page size`. 기본 `"A4 auto"`.
|
|
82
|
+
- `printAsync.options.margin` — `@page margin`. 기본 `"0"`.
|
|
83
|
+
- `getPdfBufferAsync.options.pageSize` — jsPDF page 크기. 기본 `"a4"`.
|
|
84
|
+
- `getPdfBufferAsync.options.orientation` — `"portrait"`/`"landscape"`. 기본 `"portrait"`(`"p"`).
|
|
85
|
+
- PDF 생성 시 컴포넌트 안 `.page` 클래스 요소 각각 1페이지로 처리, 없으면 컴포넌트 전체 1페이지.
|
|
86
|
+
- 인쇄 진행 동안 `SdBusyProvider.globalBusyCount` 자동 증감.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
await sdPrint.printAsync({ type: InvoicePrint, inputs: { order: data } }, { size: "A4 portrait" });
|
|
90
|
+
const buf = await sdPrint.getPdfBufferAsync({ type: InvoicePrint, inputs: { order } });
|
|
91
|
+
```
|
|
42
92
|
|
|
43
|
-
##
|
|
93
|
+
## 주의
|
|
44
94
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
95
|
+
- `SdToastProvider.try` 는 `Error` 가 아닌 throw 는 그대로 re-throw. 일반 함수에서 throw 시 반드시 Error 인스턴스 던질 것.
|
|
96
|
+
- `SdBusyContainer` 의 `min-height: 70px` 가 기본. 빈 컨테이너에서도 인디케이터 보이도록.
|
|
97
|
+
- `SdPrint.initialized` 를 컴포넌트가 true 로 안 set 하면 `wait.until` 이 영원히 대기. 비동기 데이터 로드 후 반드시 set.
|
|
@@ -1,59 +1,167 @@
|
|
|
1
1
|
# @simplysm/angular — visual
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
시각/표시 컴포넌트 (라벨·뱃지·진행률·달력·바코드·차트·에디터·주소검색) + 보조 레이아웃 컨테이너 (collapse·tab·list·gap·pagination·dropdown).
|
|
4
4
|
|
|
5
|
-
## `<sd-label>`
|
|
5
|
+
## SdLabel — `<sd-label>`
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```ts
|
|
8
|
+
theme = input<"primary"|"secondary"|"info"|"success"|"warning"|"danger"|"gray"|"blue-gray">();
|
|
9
|
+
color = input<string>(); // 직접 색상 hex
|
|
10
|
+
clickable = input(false);
|
|
11
|
+
```
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
- 작은 텍스트 뱃지. `theme` 또는 `color` 중 하나. `clickable=true` 면 커서 pointer + 호버 효과.
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
## SdNote — `<sd-note>`
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
```ts
|
|
18
|
+
theme = input<...8 themes>();
|
|
19
|
+
size = input<"sm"|"lg">();
|
|
20
|
+
inset = input(false);
|
|
21
|
+
```
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
- 정보 박스(노트). `<ng-content>` 가 본문. 페이지 안내문구.
|
|
24
|
+
|
|
25
|
+
## SdProgress — `<sd-progress>`
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
inset = input(false); size = input<"sm"|"lg">();
|
|
29
|
+
theme = input.required<...8 themes>();
|
|
30
|
+
value = input.required<number>(); // 0~100
|
|
17
31
|
```
|
|
18
32
|
|
|
19
|
-
|
|
33
|
+
- 가로 진행 바. value/100 만큼 채움.
|
|
20
34
|
|
|
21
|
-
## `<sd-calendar
|
|
35
|
+
## SdCalendar — `<sd-calendar>`
|
|
22
36
|
|
|
23
|
-
|
|
37
|
+
```ts
|
|
38
|
+
class SdCalendar<T>
|
|
39
|
+
items = input.required<T[]>();
|
|
40
|
+
getItemDateFn = input.required<(item: T, index: number) => DateOnly>();
|
|
41
|
+
yearMonth = input(new DateOnly().setDay(1));
|
|
42
|
+
weekStartDay = input(0); // 0=일요일, 1=월요일
|
|
43
|
+
minDaysInFirstWeek = input(1);
|
|
44
|
+
// 자식: <ng-template itemOf>...</ng-template> 로 셀별 아이템 렌더
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- 월별 달력 그리드. 각 날짜 셀에 해당하는 items 만 추려 itemOf 템플릿으로 렌더.
|
|
48
|
+
- `weekStartDay` — 0~6.
|
|
49
|
+
- `minDaysInFirstWeek` — 첫 주에 포함될 최소 일수(ISO 주차 규칙).
|
|
24
50
|
|
|
25
51
|
```html
|
|
26
|
-
<sd-calendar [items]="events" [getItemDateFn]="
|
|
27
|
-
<ng-template [itemOf]="events" let-item
|
|
28
|
-
<div>{{ item.title }}</div>
|
|
29
|
-
</ng-template>
|
|
52
|
+
<sd-calendar [items]="events()" [getItemDateFn]="getDate" [yearMonth]="ym()">
|
|
53
|
+
<ng-template itemOf [itemOf]="events()" let-item>{{ item.title }}</ng-template>
|
|
30
54
|
</sd-calendar>
|
|
31
55
|
```
|
|
32
56
|
|
|
33
|
-
|
|
34
|
-
- `yearMonth = input(new DateOnly().setDay(1))` (해당 월).
|
|
35
|
-
- `weekStartDay = 0`, `minDaysInFirstWeek = 1`.
|
|
36
|
-
- 필수 content: `<ng-template [itemOf]="items">` (`SdItemOfTemplate`, ctx: `$implicit/item/index/depth`).
|
|
57
|
+
## SdBarcode — `<sd-barcode>`
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
```ts
|
|
60
|
+
type = input.required<BarcodeType>();
|
|
61
|
+
value = input<string>();
|
|
39
62
|
|
|
40
|
-
|
|
63
|
+
type BarcodeType = "code128"|"qrcode"|"ean13"|"ean8"|"code39"|... (bwip-js bcid 전체)
|
|
64
|
+
```
|
|
41
65
|
|
|
42
|
-
|
|
43
|
-
|
|
66
|
+
- bwip-js 로 SVG 바코드 렌더. value 비면 빈 출력. 인식 불가 데이터면 catch 후 빈 출력.
|
|
67
|
+
|
|
68
|
+
## SdEcharts — `<sd-echarts>`
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
option = input.required<echarts.EChartsOption>();
|
|
72
|
+
notMerge = input(false); // setOption merge 비활성
|
|
73
|
+
loading = input(false); // showLoading/hideLoading
|
|
44
74
|
```
|
|
45
75
|
|
|
46
|
-
|
|
76
|
+
- ECharts 래퍼. `option` 변경 시 자동 setOption.
|
|
47
77
|
|
|
48
|
-
## `<sd-
|
|
78
|
+
## SdTiptapEditor — `<sd-tiptap-editor>`
|
|
49
79
|
|
|
50
|
-
|
|
80
|
+
```ts
|
|
81
|
+
value = model<string>(); // HTML 문자열
|
|
82
|
+
disabled = input(false); readonly = input(false); required = input(false);
|
|
83
|
+
placeholder = input<string>();
|
|
84
|
+
validatorFn = input<(value) => string|undefined>();
|
|
85
|
+
extensions = input<AnyExtension[]>(); // 추가 tiptap extensions
|
|
86
|
+
```
|
|
51
87
|
|
|
52
|
-
|
|
53
|
-
|
|
88
|
+
- WYSIWYG HTML 에디터. tiptap 기반. 기본 extension(헤딩/볼드/리스트 등) 내장.
|
|
89
|
+
|
|
90
|
+
## SdAddressSearchModal — `<sd-address-search-modal>` (SdModalContentDef<Address>)
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
close = output<Address>();
|
|
94
|
+
initialized = signal(false);
|
|
95
|
+
interface Address { postNumber: string|undefined; address: string|undefined; buildingName: string|undefined; }
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- 다음(daum) 우편번호 검색 위젯 모달. `SdModalProvider.showAsync({ type: SdAddressSearchModal, ... })` 로 호출.
|
|
99
|
+
- 다음 postcode 스크립트 로드 실패 시 에러 메시지 표시.
|
|
100
|
+
|
|
101
|
+
## SdCollapse — `<sd-collapse>`
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
open = input(false);
|
|
54
105
|
```
|
|
55
106
|
|
|
56
|
-
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
107
|
+
- 접힘/펼침 컨테이너. transition 으로 height 애니메이션. `<ng-content>` 가 본문.
|
|
108
|
+
|
|
109
|
+
## SdCollapseIcon — `<sd-collapse-icon>`
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
icon = input(tablerChevronDown);
|
|
113
|
+
open = input(false);
|
|
114
|
+
openRotate = input(90); // open 일 때 회전 각도
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- 펼침/접힘 표시 아이콘. open 토글 시 회전 애니메이션.
|
|
118
|
+
|
|
119
|
+
## SdTab — `<sd-tab>` / SdTabItem — `<sd-tab-item>`
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
class SdTab { value = model<any>(); }
|
|
123
|
+
class SdTabItem { value = input<any>(); }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- 탭 컨테이너 + 탭 항목. `<sd-tab-item value="a">A</sd-tab-item>` 클릭 시 `SdTab.value` 가 `"a"` 로.
|
|
127
|
+
|
|
128
|
+
## SdList — `<sd-list>` / SdListItem — `<sd-list-item>`
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
class SdList { inset = input(false); }
|
|
132
|
+
class SdListItem {
|
|
133
|
+
layout = input<"accordion"|"flat">("accordion");
|
|
134
|
+
open = model(false);
|
|
135
|
+
selected = input(false); selectedIcon = input<string>();
|
|
136
|
+
readonly = input(false);
|
|
137
|
+
contentStyle = input<string>(); contentClass = input<string>();
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- 세로 메뉴/리스트. `layout="accordion"` 이면 자식 리스트 펼침 가능, `flat` 이면 상시 전개.
|
|
142
|
+
- `selected=true` → 강조 + `selectedIcon` 표시.
|
|
143
|
+
|
|
144
|
+
## SdGap — `<sd-gap>`
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
height = input<"xxs"|"xs"|"sm"|"default"|"lg"|"xl"|"xxl">();
|
|
148
|
+
heightPx = input<number>();
|
|
149
|
+
width = input<"xxs"|...|"xxl">(); widthPx = input<number>(); widthEm = input<number>();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- 빈 공간 채움. 토큰 키워드(디자인 변수) 또는 px/em 직접 지정.
|
|
153
|
+
|
|
154
|
+
## SdPagination — `<sd-pagination>`
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
currentPage = model(0);
|
|
158
|
+
totalPageCount = input(0);
|
|
159
|
+
visiblePageCount = input(10);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- 페이지 번호 바. 0-based. `<sd-sheet>`/`<sd-crud-list>` 내부에서 사용되지만 단독 사용도 가능.
|
|
163
|
+
|
|
164
|
+
## 주의
|
|
165
|
+
|
|
166
|
+
- `SdCalendar` 의 자식 `<ng-template itemOf>` 의 `[itemOf]` 는 `items()` 와 같은 배열 바인딩(type token 용도).
|
|
167
|
+
- `SdBarcode` 는 `bypassSecurityTrustHtml` 사용. value 가 사용자 입력이라도 bwip-js 가 SVG 만 생성하므로 안전(코드 주입 불가).
|