@simplysm/sd-claude 14.0.98 → 14.0.99
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/references/sd-simplysm14/README.md +16 -16
- package/claude/references/sd-simplysm14/apis/angular/README.md +81 -153
- package/claude/references/sd-simplysm14/apis/angular/controls.md +179 -205
- package/claude/references/sd-simplysm14/apis/angular/crud.md +71 -57
- package/claude/references/sd-simplysm14/apis/angular/directives.md +49 -109
- package/claude/references/sd-simplysm14/apis/angular/features.md +58 -86
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +32 -40
- package/claude/references/sd-simplysm14/apis/angular/layout.md +38 -52
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +86 -110
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -86
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +82 -74
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +56 -80
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +15 -15
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -21
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +79 -53
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +9 -11
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +15 -15
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +20 -20
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +18 -18
- package/claude/references/sd-simplysm14/apis/core-common/README.md +20 -49
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +66 -55
- package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +83 -56
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +32 -21
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +57 -39
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +36 -30
- package/claude/references/sd-simplysm14/apis/core-common/value-types.md +69 -41
- package/claude/references/sd-simplysm14/apis/core-node/README.md +4 -4
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +15 -13
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +11 -7
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +8 -8
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +29 -20
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -6
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +3 -3
- package/claude/references/sd-simplysm14/apis/excel/README.md +3 -3
- package/claude/references/sd-simplysm14/apis/excel/cell.md +32 -32
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +23 -24
- package/claude/references/sd-simplysm14/apis/excel/style.md +24 -30
- package/claude/references/sd-simplysm14/apis/excel/utils.md +20 -23
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +60 -71
- package/claude/references/sd-simplysm14/apis/excel/wrapper.md +36 -36
- package/claude/references/sd-simplysm14/apis/lint/README.md +7 -9
- package/claude/references/sd-simplysm14/apis/lint/recommended.md +59 -37
- package/claude/references/sd-simplysm14/apis/lint/rules.md +81 -74
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -6
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +112 -78
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +131 -75
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +126 -82
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +170 -113
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +102 -48
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +12 -13
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +3 -3
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +5 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +67 -65
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +130 -123
- package/claude/references/sd-simplysm14/apis/service-client/README.md +63 -63
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +22 -22
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +30 -26
- package/claude/references/sd-simplysm14/apis/service-common/README.md +8 -8
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +13 -6
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-server/README.md +43 -47
- package/claude/references/sd-simplysm14/apis/service-server/built-in-services.md +35 -0
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +20 -19
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +23 -25
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +9 -9
- package/claude/references/sd-simplysm14/apis/storage/README.md +26 -26
- package/claude/references/sd-simplysm14/manuals/client-component.md +9 -1
- package/claude/references/sd-simplysm14/manuals/client-crud.md +1 -1
- package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -0
- package/claude/references/sd-simplysm14/manuals/client-service.md +1 -0
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +1 -0
- package/claude/references/sd-simplysm14/manuals/client-ssg.md +1 -0
- package/claude/sd-system-prompt.md +11 -26
- package/claude/skills/sd-docs/references/subagent-prompt.md +4 -3
- package/claude/skills/sd-spec/SKILL.md +87 -18
- package/claude/skills/sd-spec/references/format.md +2 -2
- package/package.json +1 -1
|
@@ -1,75 +1,89 @@
|
|
|
1
|
-
# @simplysm/angular — CRUD 화면
|
|
1
|
+
# @simplysm/angular — CRUD 화면 골격·권한표·상태프리셋
|
|
2
2
|
|
|
3
|
-
목록/단건 화면의 표준 컨테이너 골격. `sd-base-container`(공통 셸) 위에 `sd-crud-list`(목록)
|
|
3
|
+
목록/단건 화면의 표준 컨테이너 골격. `sd-base-container`(공통 셸) 위에 `sd-crud-list`(목록)·`sd-crud-detail`(단건)이 얹힘. 표준 시그널(`ready`/`initialized`/`busyCount`/`viewType`)·page/modal/control 컨텍스트별 탑바·하단바 자동 구성·CTRL+S 저장을 내장. 화면 작성 절차·데이터 흐름은 [client-crud.md](../manuals/client-crud.md) · [client-component.md](../manuals/client-component.md) 참조. 함께 쓰는 권한 테이블·상태 프리셋도 이 군에 둠.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
공통: 세 컨테이너 모두 `viewType: SdViewType`(required, `"page"|"modal"|"control"`)에 따라 동작이 갈림. `"page"` = 라우팅 진입(탑바에 액션), `"modal"` = 모달(하단 명령바·확인 버튼), `"control"` = view 임베드(명령 영역에 액션).
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
## `SdBaseContainer` — `<sd-base-container>`
|
|
8
|
+
|
|
9
|
+
busy 컨테이너로 감싸고(`page` 면 탑바 포함) 권한 없음 placeholder 를 제공하는 공통 셸. `SdSharedDataProvider` 로드를 기다린 뒤 `ready` 를 set.
|
|
10
|
+
|
|
11
|
+
- `ready: model(false)` — 공유데이터 로드 완료(또는 `restricted` 면 즉시) 후 자동 `true`. 자식 effect 발화 시점.
|
|
12
|
+
- `initialized: input(false)` — true 일 때만 콘텐츠 렌더. busy 스피너는 `initialized() && busyCount() > 0` 일 때.
|
|
13
|
+
- `busyCount: model(0)` — 진행 중 작업 수. `>0` 이면 busy.
|
|
14
|
+
- `restricted: input(false)` — true 면 "사용권한 없음" 메시지 렌더 + `ready` 즉시 set(공유데이터 대기 스킵).
|
|
15
|
+
- `viewType: input.required<SdViewType>` — `"page"` 면 `<sd-topbar-container>` + viewTitle 렌더, `"modal"`/`"control"` 면 탑바 없이 콘텐츠.
|
|
16
|
+
- 슬롯: `#topbarTpl`(page 탑바 추가 버튼) / `#commandTpl`(콘텐츠 위 명령바) / `#contentTpl`(본문) / `#bottomCommandTpl`(하단 명령바).
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<sd-base-container [(ready)]="ready" [initialized]="initialized()" [(busyCount)]="busyCount" [restricted]="!perms().includes('use')" [viewType]="viewType()">
|
|
20
|
+
<ng-template #contentTpl>...</ng-template>
|
|
21
|
+
</sd-base-container>
|
|
12
22
|
```
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
trackByFn = input.required<(item: TItem) => TKey>();
|
|
30
|
-
getItemSelectableFn = input<(item: TItem) => boolean | string>();
|
|
31
|
-
|
|
32
|
-
filterSubmit = output(); submit = output(); create = output();
|
|
33
|
-
delete = output<TItem[]>(); restore = output<TItem[]>();
|
|
34
|
-
// 슬롯: #filterTpl #toolTpl #commandTpl #bottomCommandTpl, 직속 <sd-sheet-column>
|
|
24
|
+
## `SdCrudDetail` — `<sd-crud-detail>`
|
|
25
|
+
|
|
26
|
+
단건 편집 폼 골격(`sd-base-container` 기반). `readonly` 가 아니면 콘텐츠를 `<sd-form>` 으로 감싸고 저장 컨트롤 제공. `SdCommandDirective` 호스트(CTRL+S → 저장).
|
|
27
|
+
|
|
28
|
+
- `ready: model(false)` / `initialized: input(false)` / `busyCount: model(0)` / `restricted: input(false)` — base 로 전달.
|
|
29
|
+
- `readonly: input(false)` — true 면 저장 버튼 숨김 + `<sd-form>` 없이 plain `<div>` 렌더(제출 불가); false 면 `<sd-form>` 래핑 + 저장 컨트롤.
|
|
30
|
+
- `viewType: input.required<SdViewType>` — `"page"` = 탑바 `#topbarTpl` 에 "저장 (CTRL+S)" 버튼; `"control"` = `#commandTpl` 에 저장 버튼; `"modal"` = 하단 명령바에 "확인" 버튼.
|
|
31
|
+
- `submit: output()` — 내부 `<sd-form>` 의 유효 제출 시 emit.
|
|
32
|
+
- 슬롯: `#contentTpl`(필수, 폼 본문) / `#commandTpl` / `#bottomCommandTpl`.
|
|
33
|
+
- 메서드: `onSaveButtonClick()` — `formCtrl().requestSubmit()`.
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<sd-crud-detail [(ready)]="ready" [initialized]="initialized()" [(busyCount)]="busyCount" [restricted]="!perms().includes('use')" [readonly]="!canEdit()" [viewType]="viewType()" (submit)="onSubmit()">
|
|
37
|
+
<ng-template #contentTpl>...</ng-template>
|
|
38
|
+
</sd-crud-detail>
|
|
35
39
|
```
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
41
|
+
## `SdCrudList<TItem, TKey>` — `<sd-crud-list>`
|
|
42
|
+
|
|
43
|
+
목록 골격(`sd-base-container` + `sd-sheet`). 시트·검색 폼·등록/삭제/복구·CTRL+S 저장·페이징·정렬·선택·인라인 편집·모달 선택을 일괄 제공. `SdCommandDirective` 호스트.
|
|
44
|
+
|
|
45
|
+
- `ready: model(false)` / `initialized: input(false)` / `busyCount: model(0)` / `restricted: input(false)` — base 로 전달.
|
|
46
|
+
- `readonly: input(false)` — true 면 등록/삭제/복구 버튼 숨김 + 인라인 편집 비활성 + 삭제 행 취소선.
|
|
47
|
+
- `inlineEdit: input(true)` — true(비-readonly)면 시트를 `<sd-form>` 으로 감싸 셀 인라인 편집 + 삭제 컬럼 + 저장. false 면 인라인 편집 chrome 제거(조회·선택 전용, `submit` 미발화).
|
|
48
|
+
- `viewType: input.required<SdViewType>` — `"page"` = 탑바 저장 버튼(인라인 편집 시); `"modal"` = 하단 선택 명령바("선택 해제", multi 면 "확인(n)").
|
|
49
|
+
- `selectMode: "single"|"multi"|undefined` — `"single"` = 선택 삭제/복구 숨김·클릭 즉시 modal close; `"multi"` = 다중 선택·삭제/복구·"확인(n)"; `undefined`(비-modal) = 비-readonly 면 `'multi'`.
|
|
50
|
+
- `key: input.required<string>` — 시트 설정 키(내부 시트는 `key()+'-sheet'`).
|
|
51
|
+
- `items: TItem[]` (기본 `[]`) — 행 데이터.
|
|
52
|
+
- `currDeletedItems: TItem[]` (기본 `[]`) — 삭제(soft delete) 행. 취소선·복구 버튼·삭제/복구 아이콘 토글에. 삭제항목 포함 검색 목록은 필수.
|
|
53
|
+
- `trackByFn: input.required<(item: TItem) => TKey>` — 키 추출(선택 멤버십·시트 추적).
|
|
54
|
+
- `getItemSelectableFn: (item) => boolean | string | undefined` — 시트로 전달, `string`=불가+툴팁.
|
|
55
|
+
- `currentPage: model(0)` / `totalPageCount: input(0)`(서버 페이징; `0`이면 useAutoSort 활성) / `itemsPerPage: input(0)`(클라이언트 페이징) / `visiblePageCount: input(10)` / `sorts: model<SortingDef[]>([])` — 시트로 전달.
|
|
56
|
+
- `selectedKeys: model<NonNullable<TKey>[]>([])` — 선택 키(시트와 양방향).
|
|
57
|
+
- output: `filterSubmit`(조회 폼 제출) / `submit`(인라인 편집 저장) / `create`(등록) / `delete: TItem[]`(삭제 대상) / `restore: TItem[]`(복구 대상).
|
|
58
|
+
- 슬롯: `#filterTpl`(검색 폼; 내부가 이미 `form-box-inline`) / `#toolTpl`(도구 버튼) / `#commandTpl` / `#bottomCommandTpl`. `<sd-sheet-column>` 직속 자식은 내부 시트로 자동 투영.
|
|
42
59
|
|
|
43
60
|
```html
|
|
44
|
-
<sd-crud-list [(ready)]="ready" [initialized]="initialized()" [(busyCount)]="busyCount"
|
|
45
|
-
[restricted]="!perms().includes('use')" [readonly]="!canEdit()" [viewType]="viewType()"
|
|
46
|
-
[key]="'role'" [items]="items()" [trackByFn]="trackByFn" [(selectedKeys)]="selectedKeys"
|
|
47
|
-
(create)="onCreate()" (delete)="onDelete($event)" (restore)="onRestore($event)">
|
|
61
|
+
<sd-crud-list [(ready)]="ready" [initialized]="initialized()" [(busyCount)]="busyCount" [restricted]="!perms().includes('use')" [readonly]="!canEdit()" [viewType]="viewType()" [selectMode]="selectMode() ?? 'multi'" [key]="'role'" [items]="items()" [currDeletedItems]="deletedItems()" [trackByFn]="trackByFn" [(selectedKeys)]="selectedKeys" [(currentPage)]="page" [totalPageCount]="pageLength()" [(sorts)]="sortingDefs" (filterSubmit)="onFilterSubmit()" (submit)="onSubmit()" (create)="onCreate()" (delete)="onDelete($event)" (restore)="onRestore($event)">
|
|
48
62
|
<ng-template #filterTpl>...</ng-template>
|
|
49
|
-
<sd-sheet-column [key]="'name'" [header]="'이름'">
|
|
50
|
-
<ng-template [cell]="items()" let-item="item">{{ item.name }}</ng-template>
|
|
51
|
-
</sd-sheet-column>
|
|
63
|
+
<sd-sheet-column [key]="'name'" [header]="'이름'"><ng-template [cell]="items()" let-item="item">...</ng-template></sd-sheet-column>
|
|
52
64
|
</sd-crud-list>
|
|
53
65
|
```
|
|
54
66
|
|
|
55
|
-
##
|
|
67
|
+
## `SdStatePreset<TState>` — `<sd-state-preset>`
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
임의 상태의 명명 스냅샷을 저장·복원(system config 영속화). 필터 프리셋 등에.
|
|
70
|
+
|
|
71
|
+
- `key: input.required<string>` — 프리셋 배열 저장 키.
|
|
72
|
+
- `state: model.required<TState>` — 현재 상태(양방향). 프리셋 클릭 시 그 상태로 set(deep clone), 저장 시 현재 상태 clone 보관.
|
|
73
|
+
- `size: "sm"|"lg"|undefined` — 추가 버튼/칩 패딩 스케일.
|
|
74
|
+
- 메서드: `onAddClick()`(이름 입력·중복 거부·추가) / `onPresetClick(preset)`(적용) / `onSaveClick(preset)`(덮어쓰기) / `onDeleteClick(preset)`(확인 후 삭제).
|
|
75
|
+
- `SdStatePresetDef<TState>` — `{ name: string; state: TState }`.
|
|
64
76
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
## `SdPermissionTable<TModule>` — `<sd-permission-table>`
|
|
78
|
+
|
|
79
|
+
권한 트리(사용/편집 체크박스)를 계층 표시. 부모/자식·use→edit 의존 규칙 강제. 권한 관리 화면에서 `getPermissionsByStructure` 결과를 넘김([client-app-structure.md](../manuals/client-app-structure.md)).
|
|
80
|
+
|
|
81
|
+
- `value: model<Record<string, boolean>>({})` — `"<codeChain>.<use|edit>" → boolean` 맵. 토글이 자식에 캐스케이드, `use` 해제 시 `edit` 자동 해제, `use` 미체크면 `edit` 체크 무시.
|
|
82
|
+
- `items: SdPermission<TModule>[]` (기본 `[]`) — 권한 트리.
|
|
83
|
+
- `disabled: boolean` — true 면 전체 체크박스 비활성.
|
|
68
84
|
|
|
69
85
|
```html
|
|
70
|
-
<sd-
|
|
71
|
-
[restricted]="!perms().includes('use')" [readonly]="!canEdit()" [viewType]="viewType()"
|
|
72
|
-
(submit)="onSubmit()">
|
|
73
|
-
<ng-template #contentTpl><!-- 폼 본문 --></ng-template>
|
|
74
|
-
</sd-crud-detail>
|
|
86
|
+
<sd-permission-table [items]="permissions()" [(value)]="data" />
|
|
75
87
|
```
|
|
88
|
+
|
|
89
|
+
(`SdPermission<TModule>` 타입은 [routing-appstructure.md](./routing-appstructure.md) 참조.)
|
|
@@ -1,167 +1,107 @@
|
|
|
1
|
-
# @simplysm/angular —
|
|
1
|
+
# @simplysm/angular — 디렉티브·signal 헬퍼
|
|
2
2
|
|
|
3
|
-
DOM 관찰(리사이즈/교차)·캡처 이벤트·커맨드 단축키·ripple·노출 애니메이션·invalid 표시·타입드 템플릿을 호스트 엘리먼트에 붙이는 디렉티브와,
|
|
3
|
+
DOM 관찰(리사이즈/교차)·캡처 이벤트·커맨드 단축키·ripple·노출 애니메이션·invalid 표시·타입드 템플릿을 호스트 엘리먼트에 붙이는 디렉티브와, 그 디렉티브가 래핑하는 `setup*` 헬퍼 군. `setup*`/`inject*` 헬퍼는 컴포넌트 `constructor`(주입 컨텍스트)에서 호출(`inject(ElementRef)` 등 의존). 모든 디렉티브는 standalone, attribute selector.
|
|
4
4
|
|
|
5
5
|
## DOM 관찰 디렉티브
|
|
6
6
|
|
|
7
|
-
### SdResizeDirective — `[sdResize]`
|
|
7
|
+
### `SdResizeDirective` — `[sdResize]`
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
sdResize = output<SdResizeEvent>();
|
|
11
|
-
// SdResizeEvent { heightChanged: boolean; widthChanged: boolean; target: HTMLElement; contentRect: DOMRectReadOnly }
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
- `ResizeObserver` 로 크기 변화를 rAF 디바운스해 방출. `heightChanged`/`widthChanged` 로 변경 축을 구분(불필요한 재계산 회피). 시트·collapse·echarts 가 사용.
|
|
9
|
+
- `sdResize: output<SdResizeEvent>` — `ResizeObserver` 기반, `requestAnimationFrame` 디바운스. `SdResizeEvent` = `{ heightChanged: boolean; widthChanged: boolean; target: HTMLElement; contentRect: DOMRectReadOnly }`.
|
|
15
10
|
|
|
16
11
|
```html
|
|
17
12
|
<div (sdResize)="onResize($event)">...</div>
|
|
18
13
|
```
|
|
19
14
|
|
|
20
|
-
### SdIntersectionDirective — `[sdIntersection]`
|
|
21
|
-
|
|
22
|
-
```ts
|
|
23
|
-
sdIntersection = output<SdIntersectionEvent>();
|
|
24
|
-
// SdIntersectionEvent { entry: IntersectionObserverEntry }
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
- `IntersectionObserver` 로 뷰포트 진입/이탈을 방출. 지연 로드·노출 트리거에 사용. `entry.isIntersecting` 으로 판정.
|
|
15
|
+
### `SdIntersectionDirective` — `[sdIntersection]`
|
|
28
16
|
|
|
29
|
-
|
|
17
|
+
- `sdIntersection: output<SdIntersectionEvent>` — `IntersectionObserver` 기반, 콜백 배치의 마지막 엔트리 emit. `SdIntersectionEvent` = `{ entry: IntersectionObserverEntry }`.
|
|
30
18
|
|
|
31
|
-
|
|
19
|
+
## 캡처/옵션 이벤트
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
// selector 의 각 어트리뷰트가 output. 예:
|
|
35
|
-
"click.capture", "click.once", "scroll.passive", "wheel.passive",
|
|
36
|
-
"touchstart.passive", "keydown.capture", "focus.capture", "blur.capture",
|
|
37
|
-
"invalid.capture", "transitionend.once", "animationend.once" ...
|
|
38
|
-
```
|
|
21
|
+
### `SdEvents` (디렉티브)
|
|
39
22
|
|
|
40
|
-
|
|
23
|
+
native DOM 리스너 옵션(`capture`/`passive`/`once`)을 이벤트명 접미사로 노출하는 디렉티브. `SdOptionEventPlugin` 과 함께 동작. 출력은 접미사 그대로의 이름: `click.capture`/`click.once`/`click.capture.once`, `mousedown.capture`/`mouseup.capture`/`mouseover.capture`/`mouseout.capture`, `keydown.capture`/`keyup.capture`, `focus.capture`/`blur.capture`, `invalid.capture`, `scroll.capture`/`scroll.passive`/`scroll.capture.passive`, `wheel.passive`/`wheel.capture.passive`, `touchstart.passive`/`touchmove.passive`/`touchend.passive`(및 `.capture.passive` 변형), `dragover.capture`/`dragenter.capture`/`dragleave.capture`/`drop.capture`, `transitionend.once`, `animationend.once`. 각 출력의 페이로드 타입은 해당 native 이벤트(`MouseEvent`/`KeyboardEvent`/`FocusEvent`/`DragEvent`/`WheelEvent`/`TouchEvent`/`TransitionEvent`/`AnimationEvent`/`Event`).
|
|
41
24
|
|
|
42
25
|
```html
|
|
43
|
-
<div (
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### SdOptionEventPlugin
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
class SdOptionEventPlugin extends EventManagerPlugin
|
|
26
|
+
<div (keydown.capture)="onKeydownCapture($event)" (scroll.passive)="onScroll($event)">...</div>
|
|
50
27
|
```
|
|
51
28
|
|
|
52
|
-
|
|
29
|
+
### `SdOptionEventPlugin`
|
|
53
30
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
sdRefreshCommand = output<KeyboardEvent>(); // Ctrl+Alt+L
|
|
58
|
-
sdSaveCommand = output<KeyboardEvent>(); // Ctrl+S
|
|
59
|
-
sdInsertCommand = output<KeyboardEvent>(); // Insert
|
|
60
|
-
```
|
|
31
|
+
`EventManagerPlugin` 확장(`provideSdAngular` 가 `EVENT_MANAGER_PLUGINS` multi 로 등록). 이벤트명 접미사 `.capture`/`.passive`/`.once` 를 native 리스너 옵션으로 변환. 위 `SdEvents` 출력이 이 플러그인 위에서 동작.
|
|
61
32
|
|
|
62
|
-
|
|
33
|
+
## 커맨드 단축키
|
|
63
34
|
|
|
64
|
-
###
|
|
35
|
+
### `SdCommandDirective` — `[sdRefreshCommand],[sdSaveCommand],[sdInsertCommand]`
|
|
65
36
|
|
|
66
|
-
|
|
67
|
-
class SdGlobalErrorHandlerPlugin implements ErrorHandler
|
|
68
|
-
```
|
|
37
|
+
전역 키 조합을 받아 출력으로 발화하는 디렉티브. 호스트가 최상위 열린 모달 안이거나 모달이 없을 때만 처리.
|
|
69
38
|
|
|
70
|
-
-
|
|
39
|
+
- `sdRefreshCommand: output<KeyboardEvent>` — `Ctrl+Alt+L`.
|
|
40
|
+
- `sdSaveCommand: output<KeyboardEvent>` — `Ctrl+S`(Alt 없이). `sd-crud-list`/`sd-crud-detail` 이 hostDirective 로 사용해 저장에 배선.
|
|
41
|
+
- `sdInsertCommand: output<KeyboardEvent>` — `Ctrl+Insert`.
|
|
71
42
|
|
|
72
|
-
##
|
|
43
|
+
## ripple
|
|
73
44
|
|
|
74
|
-
### setupRipple
|
|
45
|
+
### `setupRipple`
|
|
75
46
|
|
|
76
47
|
```ts
|
|
77
|
-
setupRipple(enableFn?: () => boolean): void
|
|
78
|
-
// SdRipple: enabled = input.required({ alias: "sdRipple", transform: booleanAttribute });
|
|
48
|
+
function setupRipple(enableFn?: () => boolean): void
|
|
79
49
|
```
|
|
80
50
|
|
|
81
|
-
-
|
|
51
|
+
- 주입 컨텍스트에서 호출. 호스트를 `position:relative; overflow:hidden` 으로 만들고 `pointerdown` 시 확장 원형 ripple 생성. `enableFn` 이 false 반환 시 스킵. SSR no-op.
|
|
82
52
|
|
|
83
|
-
###
|
|
53
|
+
### `SdRipple` — `[sdRipple]`
|
|
84
54
|
|
|
85
|
-
|
|
86
|
-
setupRevealOnShow(optFn?: () => { type?: "l2r" | "t2b"; enabled?: boolean }): void;
|
|
87
|
-
// SdShowEffect: enabled = input.required({ alias: "sdShowEffect" }); sdShowEffectType = input<"l2r"|"t2b">("t2b");
|
|
88
|
-
```
|
|
55
|
+
- `enabled: input.required({ alias: "sdRipple", transform: booleanAttribute })` — 속성값을 boolean 으로. `setupRipple(() => enabled())` 배선.
|
|
89
56
|
|
|
90
|
-
|
|
57
|
+
## 노출 애니메이션
|
|
91
58
|
|
|
92
|
-
###
|
|
59
|
+
### `setupRevealOnShow`
|
|
93
60
|
|
|
94
61
|
```ts
|
|
95
|
-
|
|
96
|
-
// SdInvalid: invalidMessage = input.required<string>({ alias: "sdInvalid" });
|
|
62
|
+
function setupRevealOnShow(optFn?: () => { type?: "l2r" | "t2b"; enabled?: boolean }): void
|
|
97
63
|
```
|
|
98
64
|
|
|
99
|
-
-
|
|
65
|
+
- 초기 숨김(opacity 0 + 이동) 후 `IntersectionObserver` 로 화면 진입 시 슬라이드-인. `type` = `"l2r"`(좌→우) / `"t2b"`(위→아래, 기본). `enabled` 기본 true(false 면 즉시 표시).
|
|
100
66
|
|
|
101
|
-
|
|
67
|
+
### `SdShowEffect` — `[sdShowEffect]`
|
|
102
68
|
|
|
103
|
-
|
|
69
|
+
- `enabled: input.required({ alias: "sdShowEffect", transform: booleanAttribute })`.
|
|
70
|
+
- `sdShowEffectType: input<"l2r" | "t2b">("t2b")` — 노출 방향.
|
|
104
71
|
|
|
105
|
-
|
|
106
|
-
typed = input.required<T>();
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
- `ng-template` 컨텍스트 타입을 명시(`ngTemplateContextGuard`). 재귀 메뉴/트리 템플릿에서 `let-x` 의 타입 안전성 확보. `[typed]` 에 타입 토큰을 넘김.
|
|
72
|
+
## invalid 표시
|
|
110
73
|
|
|
111
|
-
###
|
|
74
|
+
### `setupInvalid`
|
|
112
75
|
|
|
113
76
|
```ts
|
|
114
|
-
|
|
115
|
-
// SdItemOfTemplateContext<TItem> { $implicit; item; index; depth }
|
|
77
|
+
function setupInvalid(getInvalidMessage: () => string): void
|
|
116
78
|
```
|
|
117
79
|
|
|
118
|
-
-
|
|
80
|
+
- 호스트에 danger 인디케이터 점 + 숨김 input(native validity 운반)을 주입. `getInvalidMessage()` 가 빈 문자열이 아니면 invalid(점 표시·`setCustomValidity`). `sd-form` 의 `checkValidity()` 에 연동. 모든 검증 컨트롤(`sd-textfield` 등)의 내부 기반.
|
|
119
81
|
|
|
120
|
-
|
|
82
|
+
### `SdInvalid` — `[sdInvalid]`
|
|
121
83
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
setupModelHook<T>(model: WritableSignal<T>, canFn: Signal<(item: T) => boolean | Promise<boolean>>): void;
|
|
126
|
-
```
|
|
84
|
+
- `invalidMessage: input.required<string>({ alias: "sdInvalid" })` — 비어있지 않으면 호스트를 invalid 표시.
|
|
127
85
|
|
|
128
|
-
|
|
86
|
+
## 타입드 템플릿
|
|
129
87
|
|
|
130
|
-
###
|
|
88
|
+
### `SdTypedTemplate<T>` — `ng-template[typed]`
|
|
131
89
|
|
|
132
|
-
|
|
133
|
-
mark(sig: WritableSignal<any>): void;
|
|
134
|
-
```
|
|
90
|
+
- `typed: input.required<T>()` — 템플릿 컨텍스트 타입을 정하는 값. 정적 `ngTemplateContextGuard` 로 컨텍스트를 `T` 로 좁힘.
|
|
135
91
|
|
|
136
|
-
|
|
92
|
+
### `SdItemOfTemplate<TItem>` — `ng-template[itemOf]`
|
|
137
93
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
setSafeStyle(renderer: Renderer2, el: HTMLElement, style: Partial<CSSStyleDeclaration>): void;
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
- `Renderer2.setStyle` 로 여러 스타일을 한 번에 적용하는 헬퍼(키별 순회). `style` 객체의 각 CSS 속성을 엘리먼트에 설정. 디렉티브/composable 에서 DOM 스타일을 안전하게 줄 때 사용(`setupInvalid` 등이 내부 사용).
|
|
145
|
-
|
|
146
|
-
### FormatPipe — `| format`
|
|
147
|
-
|
|
148
|
-
```ts
|
|
149
|
-
@Pipe({ name: "format" }) transform(value: string | DateTime | DateOnly | undefined, format: string): string;
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
- 값 포맷. `DateTime`/`DateOnly` 는 `toFormatString(format)`, 문자열은 `X` 마스크(`|` 로 길이 분기). null 이면 빈 문자열(결측 보존). calendar 등이 사용.
|
|
94
|
+
- `itemOf: input.required<TItem[]>()` — 항목 배열; 원소 타입으로 per-item 컨텍스트를 정함. 공유데이터 select·calendar 등 항목 렌더 템플릿에 사용.
|
|
95
|
+
- `SdItemOfTemplateContext<TItem>` = `{ $implicit: TItem; item: TItem; index: number; depth: number }`. 템플릿에서 `let-item="item"` 등으로 받음.
|
|
153
96
|
|
|
154
97
|
```html
|
|
155
|
-
|
|
98
|
+
<sd-shared-data-select [items]="sharedCustomers.items()" ...>
|
|
99
|
+
<ng-template [itemOf]="sharedCustomers.items()" let-item="item">{{ item.name }}</ng-template>
|
|
100
|
+
</sd-shared-data-select>
|
|
156
101
|
```
|
|
157
102
|
|
|
158
|
-
|
|
103
|
+
## 전역 에러 핸들러
|
|
159
104
|
|
|
160
|
-
|
|
161
|
-
DirectiveInputSignals<T> // 컴포넌트의 InputSignal 프로퍼티 → 값 타입 매핑(undefined 포함 필드는 optional)
|
|
162
|
-
UndefToOptional<T> // undefined 포함 프로퍼티를 optional 로 변환
|
|
163
|
-
WithOptional<T, K> // 특정 키 K 를 optional 로
|
|
164
|
-
SelectModalOutputResult<TKey> { selectedKeys: TKey[] } // 선택 모달 close 페이로드
|
|
165
|
-
```
|
|
105
|
+
### `SdGlobalErrorHandlerPlugin`
|
|
166
106
|
|
|
167
|
-
|
|
107
|
+
Angular `ErrorHandler` 구현(`provideSdAngular` 가 `ErrorHandler` 로 등록). `handleError(event)` — 브라우저에서 에러를 분류해 1회 전체화면 오버레이 표시 + `SdSystemLogProvider` 적재 + 앱 파괴(클릭 시 새로고침). SSR 에선 로깅만. 직접 호출할 일은 없고 등록만.
|
|
@@ -1,122 +1,94 @@
|
|
|
1
|
-
# @simplysm/angular —
|
|
1
|
+
# @simplysm/angular — features(테마·주소·에디터·시각화)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
테마 토글·폰트 크기, 주소 검색 모달, 리치텍스트 에디터, 라벨·노트·진행률·캘린더·바코드·차트 등 표시용 컴포넌트 모음. 특정 화면 기능을 붙일 때 개별로 읽힘.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 테마
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
value = model<Record<string, boolean>>({}); // "<코드>.use"/"<코드>.edit" → boolean
|
|
9
|
-
items = input<SdPermission<TModule>[]>([]);
|
|
10
|
-
disabled = input(false);
|
|
11
|
-
```
|
|
7
|
+
### `SdThemeProvider`
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
- use 미체크면 edit 불가, use 해제 시 edit 자동 해제, 부모 토글 시 하위 일괄 변경. `disabled`=전체 읽기전용. 권한 관리 화면에 사용.
|
|
9
|
+
`@Injectable({ providedIn: "root" })`. (`provideSdAngular` 가 dark/fontSize 를 `SdLocalStorageProvider` 에 영속화)
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
- `dark: WritableSignal<boolean>` (초기 false) — `effect` 로 body `sd-theme-dark` 클래스 토글(브라우저 전용).
|
|
12
|
+
- `fontSize: WritableSignal<number>` (초기 12) — `effect` 로 `documentElement.style.fontSize` 설정.
|
|
13
|
+
- `fontSizePresets: readonly number[]` = `[12, 14, 16, 20, 24, 28]`.
|
|
14
|
+
- `increaseFontSize()` / `decreaseFontSize()` — 다음/이전 프리셋으로(경계에서 no-op).
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
key = input.required<string>(); state = model.required<TState>(); size = input<"sm"|"lg">();
|
|
20
|
-
// SdStatePresetDef<TState> { name: string; state: TState }
|
|
21
|
-
```
|
|
16
|
+
### `SdThemeSelector` — `<sd-theme-selector>`
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
- `key` 로 `injectSdSystemConfigResource` 에 영속. `state` 는 화면이 들고 있는 상태 시그널(양방향).
|
|
18
|
+
팔레트 아이콘 드롭다운(폰트 +/- · 다크모드 스위치). input 없음. `isMinFontSize`/`isMaxFontSize: computed` 로 +/- 버튼 비활성.
|
|
25
19
|
|
|
26
|
-
##
|
|
20
|
+
## 주소
|
|
27
21
|
|
|
28
|
-
###
|
|
22
|
+
### `SdAddressSearchModal` — `<sd-address-search-modal>`
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
// 입력 없음. SdThemeProvider 를 inject.
|
|
32
|
-
```
|
|
24
|
+
Daum 우편번호 위젯 모달. `SdModalContentDef<Address>` 구현 — `_sdModal.showAsync({ type: SdAddressSearchModal, ... })` 로 띄움.
|
|
33
25
|
|
|
34
|
-
-
|
|
26
|
+
- input 없음. `close: output<Address>` — 선택 완료 시 주소 emit.
|
|
27
|
+
- `Address` = `{ postNumber: string | undefined; address: string | undefined; buildingName: string | undefined }`.
|
|
35
28
|
|
|
36
|
-
##
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
close = output<Address>(); // SdModalContentDef<Address>
|
|
40
|
-
// Address { postNumber: string | undefined; address: string | undefined; buildingName: string | undefined }
|
|
41
|
-
```
|
|
29
|
+
## 에디터
|
|
42
30
|
|
|
43
|
-
|
|
31
|
+
### `SdTiptapEditor` — `<sd-tiptap-editor>`
|
|
44
32
|
|
|
45
|
-
|
|
46
|
-
const addr = await this._sdModal.showAsync({ title: "주소 검색", type: SdAddressSearchModal, inputs: {} });
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## SdTiptapEditor — `<sd-tiptap-editor>`
|
|
50
|
-
|
|
51
|
-
```ts
|
|
52
|
-
value = model<string>(); // HTML
|
|
53
|
-
disabled; readonly; required; placeholder = input<string>();
|
|
54
|
-
validatorFn = input<(value: string | undefined) => string | undefined>();
|
|
55
|
-
extensions = input<AnyExtension[]>();
|
|
56
|
-
editor: WritableSignal<Editor | undefined>; // @internal — TipTap 인스턴스
|
|
57
|
-
```
|
|
33
|
+
툴바 내장 리치텍스트(TipTap) 에디터.
|
|
58
34
|
|
|
59
|
-
-
|
|
60
|
-
- `
|
|
35
|
+
- `value: model<string>` — HTML 콘텐츠(비면 `undefined`).
|
|
36
|
+
- `disabled: boolean` — true 면 툴바 숨김 + 비편집.
|
|
37
|
+
- `readonly: boolean` — 비편집(기본 커서 유지). 편집 가능 = `!disabled && !readonly`.
|
|
38
|
+
- `required: boolean` — 빈 값일 때 "값을 입력하세요.".
|
|
39
|
+
- `placeholder: string` — Placeholder 확장 추가(`extensions` 미지정 시).
|
|
40
|
+
- `validatorFn: (value) => string | undefined` — 커스텀 검증.
|
|
41
|
+
- `extensions: AnyExtension[]` — 기본 확장 셋 전체 override.
|
|
42
|
+
- 기본 확장: StarterKit·TextStyle·Color·Highlight·TextAlign·Image(base64)·Underline(+placeholder 시 Placeholder). 툴바: h1/h2·bold/italic/underline/strike·텍스트/배경색·리스트·들여쓰기·인용·코드블록·정렬·clean.
|
|
61
43
|
|
|
62
44
|
## 시각화
|
|
63
45
|
|
|
64
|
-
### SdLabel — `<sd-label>`
|
|
46
|
+
### `SdLabel` — `<sd-label>`
|
|
65
47
|
|
|
66
|
-
|
|
67
|
-
theme
|
|
68
|
-
|
|
69
|
-
```
|
|
48
|
+
- `theme: "primary"|...|"blue-gray"|undefined` — 배경(`--theme-{key}-default`; 미지정 시 gray-darker).
|
|
49
|
+
- `color: string` — 명시 배경색(theme 보다 우선).
|
|
50
|
+
- `clickable: boolean` — true 면 포인터 커서 + hover 진해짐.
|
|
70
51
|
|
|
71
|
-
|
|
52
|
+
### `SdNote` — `<sd-note>`
|
|
72
53
|
|
|
73
|
-
|
|
54
|
+
- `theme: "primary"|...|"blue-gray"|undefined` — `--theme-{key}-lightest` 배경+테두리(미지정 시 gray-lightest, 테두리 없음).
|
|
55
|
+
- `size: "sm"|"lg"` — `"sm"` 작은 폰트/패딩, `"lg"` 큰 패딩.
|
|
56
|
+
- `inset: boolean` — true 면 라운드 제거(flush).
|
|
74
57
|
|
|
75
|
-
|
|
76
|
-
theme = input<...8색>(); size = input<"sm"|"lg">(); inset = input(false);
|
|
77
|
-
```
|
|
58
|
+
### `SdProgress` — `<sd-progress>`
|
|
78
59
|
|
|
79
|
-
-
|
|
60
|
+
- `theme: input.required<"primary"|...|"blue-gray">` — 진행 바 색(`--theme-{key}-default`).
|
|
61
|
+
- `value: input.required<number>` — 0~1 비율(퍼센트 표시).
|
|
62
|
+
- `inset: boolean` — true 면 라운드/테두리 제거. `size: "sm"|"lg"` — 패딩.
|
|
80
63
|
|
|
81
|
-
###
|
|
64
|
+
### `SdCalendar<T>` — `<sd-calendar>`
|
|
82
65
|
|
|
83
|
-
|
|
84
|
-
theme = input.required<...8색>(); value = input.required<number>(); // 0~1
|
|
85
|
-
inset; size = input<"sm"|"lg">();
|
|
86
|
-
```
|
|
66
|
+
6×7 월 그리드에 일자별 항목 투영.
|
|
87
67
|
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
yearMonth = input(new DateOnly().setDay(1));
|
|
95
|
-
weekStartDay = input(0); minDaysInFirstWeek = input(1);
|
|
96
|
-
itemTplRef = contentChild.required(SdItemOfTemplate); // [itemOf] 셀 항목 템플릿(필수)
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
- 월간 캘린더. `getItemDateFn` 으로 각 항목의 날짜를 산출해 해당 칸에 `[itemOf]` 템플릿으로 렌더. `yearMonth`=표시 월, `weekStartDay`=주 시작 요일(0=일), `minDaysInFirstWeek`=첫 주 판정.
|
|
68
|
+
- `items: input.required<T[]>` — 데이터.
|
|
69
|
+
- `getItemDateFn: input.required<(item, index) => DateOnly>` — 항목→일자 매핑.
|
|
70
|
+
- `yearMonth: DateOnly` (기본 이번달 1일) — 표시 월(밖 일자는 `not-current` 클래스).
|
|
71
|
+
- `weekStartDay: number` (기본 0=일요일) — 첫 열 요일.
|
|
72
|
+
- `minDaysInFirstWeek: number` (기본 1) — 첫 주 시작 계산.
|
|
73
|
+
- 콘텐츠: `[itemOf]` 항목 템플릿(필수).
|
|
100
74
|
|
|
101
75
|
```html
|
|
102
|
-
<sd-calendar [items]="
|
|
103
|
-
<ng-template [itemOf]="
|
|
76
|
+
<sd-calendar [items]="events()" [getItemDateFn]="getDate" [(yearMonth)]="month">
|
|
77
|
+
<ng-template [itemOf]="events()" let-item="item">{{ item.title }}</ng-template>
|
|
104
78
|
</sd-calendar>
|
|
105
79
|
```
|
|
106
80
|
|
|
107
|
-
### SdBarcode — `<sd-barcode>`
|
|
81
|
+
### `SdBarcode` — `<sd-barcode>`
|
|
108
82
|
|
|
109
|
-
|
|
110
|
-
type = input.required<BarcodeType>(); value = input<string>();
|
|
111
|
-
// BarcodeType: "qrcode"|"code128"|"ean13"|"datamatrix"|... (bwip-js 전체 심볼 유니온)
|
|
112
|
-
```
|
|
83
|
+
bwip-js 로 바코드/QR 을 인라인 SVG 렌더.
|
|
113
84
|
|
|
114
|
-
-
|
|
85
|
+
- `type: input.required<BarcodeType>` — bwip-js `bcid`(심볼로지). `BarcodeType` 은 bwip-js 전 심볼로지 문자열 union(예 `"qrcode"`·`"code128"`·`"code39"`·`"ean13"`·`"datamatrix"`·`"pdf417"`·`"upca"` 등 ~150종).
|
|
86
|
+
- `value: string` — 바코드 텍스트(비면 미렌더).
|
|
115
87
|
|
|
116
|
-
### SdEcharts — `<sd-echarts>`
|
|
88
|
+
### `SdEcharts` — `<sd-echarts>`
|
|
117
89
|
|
|
118
|
-
|
|
119
|
-
option = input.required<echarts.EChartsOption>(); notMerge = input(false); loading = input(false);
|
|
120
|
-
```
|
|
90
|
+
Apache ECharts(SVG) 래퍼. `SdResizeDirective` hostDirective 로 자동 리사이즈.
|
|
121
91
|
|
|
122
|
-
-
|
|
92
|
+
- `option: input.required<echarts.EChartsOption>` — 차트 옵션(반응형 `setOption`).
|
|
93
|
+
- `notMerge: boolean` (기본 false) — true 면 이전 옵션과 병합 없이 교체.
|
|
94
|
+
- `loading: boolean` (기본 false) — true 면 `showLoading()`, false 면 `hideLoading()`.
|