@simplysm/sd-claude 14.0.91 → 14.0.93

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.
Files changed (93) hide show
  1. package/claude/references/sd-simplysm14/README.md +7 -6
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +59 -39
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +119 -186
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +70 -31
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +55 -57
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +86 -105
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +48 -57
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +37 -47
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +82 -74
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +61 -50
  11. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +74 -57
  12. package/claude/references/sd-simplysm14/apis/angular/sheet.md +63 -72
  13. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +23 -18
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -19
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +23 -18
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +72 -32
  17. package/claude/references/sd-simplysm14/apis/core-browser/README.md +18 -18
  18. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +29 -29
  19. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +41 -41
  20. package/claude/references/sd-simplysm14/apis/core-common/README.md +97 -90
  21. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +75 -51
  22. package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +81 -0
  23. package/claude/references/sd-simplysm14/apis/core-common/errors.md +27 -29
  24. package/claude/references/sd-simplysm14/apis/core-common/obj.md +44 -45
  25. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +34 -33
  26. package/claude/references/sd-simplysm14/apis/core-common/value-types.md +86 -0
  27. package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -6
  28. package/claude/references/sd-simplysm14/apis/core-node/consola.md +3 -0
  29. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +2 -2
  30. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +1 -1
  31. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +2 -2
  32. package/claude/references/sd-simplysm14/apis/core-node/worker.md +6 -3
  33. package/claude/references/sd-simplysm14/apis/excel/README.md +10 -10
  34. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +4 -2
  35. package/claude/references/sd-simplysm14/apis/excel/utils.md +1 -1
  36. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +6 -6
  37. package/claude/references/sd-simplysm14/apis/lint/README.md +6 -32
  38. package/claude/references/sd-simplysm14/apis/lint/recommended.md +60 -0
  39. package/claude/references/sd-simplysm14/apis/lint/rules.md +17 -17
  40. package/claude/references/sd-simplysm14/apis/orm-common/README.md +15 -6
  41. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +68 -102
  42. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +75 -89
  43. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +87 -99
  44. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +110 -147
  45. package/claude/references/sd-simplysm14/apis/orm-common/types.md +48 -51
  46. package/claude/references/sd-simplysm14/apis/orm-node/README.md +8 -13
  47. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +5 -5
  48. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +9 -6
  49. package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +9 -8
  50. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +23 -19
  51. package/claude/references/sd-simplysm14/apis/service-client/README.md +20 -12
  52. package/claude/references/sd-simplysm14/apis/service-client/orm.md +6 -6
  53. package/claude/references/sd-simplysm14/apis/service-client/transport.md +1 -1
  54. package/claude/references/sd-simplysm14/apis/service-common/README.md +35 -32
  55. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +23 -22
  56. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +23 -23
  57. package/claude/references/sd-simplysm14/apis/service-server/README.md +51 -43
  58. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +6 -6
  59. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +31 -21
  60. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +8 -8
  61. package/claude/references/sd-simplysm14/apis/storage/README.md +55 -49
  62. package/claude/references/sd-simplysm14/manuals/client-component.md +843 -740
  63. package/claude/references/sd-simplysm14/manuals/client-crud.md +8 -0
  64. package/claude/references/sd-simplysm14/manuals/client-demo.md +6 -16
  65. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +26 -0
  66. package/claude/references/sd-simplysm14/manuals/logging.md +1 -1
  67. package/claude/references/sd-simplysm14/manuals/orm.md +15 -1
  68. package/claude/rules/sd-design-rules.md +7 -0
  69. package/claude/sd-system-prompt.md +5 -8
  70. package/claude/skills/sd-debug/SKILL.md +43 -0
  71. package/claude/skills/sd-debug/workflow.js +390 -0
  72. package/claude/skills/sd-demo/SKILL.md +18 -20
  73. package/claude/skills/sd-dev/SKILL.md +127 -24
  74. package/claude/skills/sd-docs/SKILL.md +5 -3
  75. package/claude/skills/sd-docs/references/subagent-prompt.md +2 -3
  76. package/claude/skills/sd-impl/SKILL.md +18 -18
  77. package/claude/skills/sd-manual/SKILL.md +1 -0
  78. package/claude/skills/sd-review/SKILL.md +24 -18
  79. package/claude/skills/sd-review/workflow.js +324 -0
  80. package/claude/skills/sd-spec/SKILL.md +96 -679
  81. package/claude/skills/sd-spec/references/example-spec.md +28 -50
  82. package/claude/skills/sd-spec/references/format-analyze.md +232 -0
  83. package/claude/skills/sd-spec/references/format-design.md +248 -0
  84. package/claude/skills/sd-spec/workflow-analyze.js +615 -0
  85. package/claude/skills/sd-spec/workflow-design.js +667 -0
  86. package/claude/skills/sd-unpack/scripts/handlers/office_com.py +5 -1
  87. package/package.json +1 -1
  88. package/scripts/postinstall.mjs +157 -18
  89. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -68
  90. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +0 -77
  91. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +0 -86
  92. package/claude/skills/sd-skill/SKILL.md +0 -245
  93. package/claude/skills/sd-skill/scripts/run_eval.py +0 -380
@@ -1,91 +1,82 @@
1
- # @simplysm/angular — 부트스트랩·전역 프로바이더
1
+ # @simplysm/angular — 부트스트랩·전역 설정
2
2
 
3
- 앱 시작 시 1회 배선하는 `provideSdAngular` 와, `providedIn: "root"` 로 어디서든 inject 하는 전역 프로바이더(테마·로컬스토리지·시스템설정·시스템로그·서비스클라이언트·설정값)를 모은 군. 화면이 아니라 부트스트랩(`provideAppInitializer`)·앱 코드에서 같이 읽힌다.
3
+ 앱 시작 시 1회 배선하는 `provideSdAngular` 와, `providedIn: "root"` 로 어디서든 inject 하는 전역 프로바이더(테마·로컬스토리지·시스템설정·시스템로그·서비스클라이언트)를 모은 군. 화면보다 부트스트랩(`provideAppInitializer`)·앱 셸·설정 코드에서 같이 읽힌다.
4
4
 
5
5
  ## provideSdAngular
6
6
 
7
- ```ts
8
- function provideSdAngular(opt: { clientName: string }): EnvironmentProviders
9
- ```
7
+ zoneless Angular 앱의 핵심 프로바이더 묶음을 `EnvironmentProviders` 로 생성. `bootstrapApplication` 의 `providers` 에 한 번 넣음.
10
8
 
11
- `ApplicationConfig.providers` 1개 넣으면 simplysm 클라이언트 동작 전체가 배선됨. 내부 처리:
9
+ - `opt.clientName: string` 클라이언트 식별명. `SdAngularConfigProvider.clientName` 으로 저장되어 로컬스토리지 prefix·서비스 클라이언트 연결명에 쓰임.
12
10
 
13
- - `clientName` 클라이언트의 식별 이름. `SdAngularConfigProvider.clientName` 으로 보관되어 로컬스토리지 prefix, 서비스 클라이언트 이름, 시스템 로그 `clientName` 등에 사용. `provideSdAngular({ clientName: CLIENT_NAME })` 형태로 전달하며, 시스템 로그 배선같은 값을 씀(`client-system-log.md`).
14
- - ng-icons 전역 설정(strokeWidth 1.5, size 1.33em), `IMAGE_CONFIG`(이미지 경고 비활성), `provideZonelessChangeDetection()`.
15
- - 테마(dark/fontSize) 를 `SdLocalStorageProvider` 와 양방향 동기화(저장값 복원 + 변경 시 저장).
16
- - `window` 의 `unhandledrejection`/`error` 를 `ErrorHandler` 로 위임 + `ErrorHandler` 를 `SdGlobalErrorHandlerPlugin` 으로 교체(미처리 에러를 전체화면 표시 + 시스템로그 적재).
17
- - `EVENT_MANAGER_PLUGINS` 에 `SdOptionEventPlugin`(capture/passive/once 이벤트 옵션 지원) 추가.
18
- - service-worker(`SwUpdate`) 가 있으면 5분 주기(실패 시 지수 백오프, 최대 1시간)로 업데이트 확인 후 사용자 confirm → reload.
19
- - 라우터가 있으면 네비게이션 시작/종료에 `SdBusyProvider.globalBusyCount` 를 ±1 → 전역 busy 표시.
11
+ 배선 내용(본문 기준): zoneless 변경 감지, ng-icons 기본 설정(stroke 1.5, size 1.33em), `IMAGE_CONFIG` 경고 끔, 전역 `ErrorHandler` `SdGlobalErrorHandlerPlugin` 으로, `EVENT_MANAGER_PLUGINS` `SdOptionEventPlugin` 추가, `window` `error`/`unhandledrejection` `ErrorHandler` 위임, 저장된 dark/fontSize `SdThemeProvider` 복원하고 변경 로컬스토리지에 영속, 서비스워커 업데이트 주기 폴링(확인 새로고침 prompt, 실패 시 지수 백오프), 라우터 네비게이션 동안 `SdBusyProvider.globalBusyCount` 증감.
20
12
 
21
- 사용: `bootstrapApplication(AppRoot, { providers: [provideSdAngular({ clientName: CLIENT_NAME }), provideRouter(...), ...] })`.
13
+ ```ts
14
+ bootstrapApplication(AppComponent, {
15
+ providers: [provideSdAngular({ clientName: "wms-admin" }), provideRouter(routes)],
16
+ });
17
+ ```
22
18
 
23
19
  ## SdAngularConfigProvider
24
20
 
25
- - `clientName: string` — `provideSdAngular` 가 주입하는 클라이언트 이름. 다른 provider prefix/식별자로 참조. 보통 직접 set 하지 않음.
21
+ `provideSdAngular` 가 채우는 전역 설정 보관소. 직접 set 하지 않고 `provideSdAngular(opt)` 주입됨.
22
+
23
+ - `clientName: string` — 앱 식별명. 로컬스토리지 키·서비스 클라이언트명으로 참조.
26
24
 
27
25
  ## SdThemeProvider
28
26
 
29
- 다크모드·기본 글자크기 전역 상태. `provideSdAngular` 가 로컬스토리지 동기화를 자동 배선하므로 화면에서는 토글만 호출.
27
+ 다크모드·글자크기 전역 상태. `provideSdAngular` 가 로컬스토리지와 동기화. `sd-theme-selector` 프로바이더를 토글.
30
28
 
31
- - `dark: WritableSignal<boolean>` — 다크모드 on/off. true 면 `<body>` 에 `sd-theme-dark` 클래스 토글. 테마 전환 UI 에서 set.
32
- - `fontSize: WritableSignal<number>` — 루트 폰트 크기(px). 변경 시 `<html>` 의 `font-size` 적용(전체 rem 기준 스케일).
33
- - `fontSizePresets: readonly number[]` — `[12,14,16,20,24,28]`. 증감 단계 후보.
34
- - `increaseFontSize(): void` / `decreaseFontSize(): void` — presets 안에서 한 단계 위/아래로 이동. 경계면 무변경.
35
- - 사용: 테마 선택 UI 는 `sd-theme-selector`(features.md) 가 이 provider 를 래핑. 직접 다크 토글은 `inject(SdThemeProvider).dark.update(v => !v)`.
29
+ - `dark: WritableSignal<boolean>` — 다크 모드 여부. true 면 `document.body` 에 `sd-theme-dark` 클래스 토글. 다크/라이트 전환 시.
30
+ - `fontSize: WritableSignal<number>` — 루트 글자 크기(px). 변경 시 `documentElement.style.fontSize` 반영.
31
+ - `fontSizePresets: readonly number[]` — 선택 가능한 글자 크기 단계(`[12,14,16,20,24,28]`).
32
+ - `increaseFontSize()` / `decreaseFontSize()` — 프리셋에서 한 단계 위/아래로 이동.
36
33
 
37
34
  ## SdLocalStorageProvider<T>
38
35
 
39
- `localStorage` `<clientName>.<key>` 네임스페이스로 JSON 직렬화해 읽고 씀. 제네릭 `T` 로 키→값 타입 매핑.
36
+ `clientName` prefix 붙여 `localStorage` 에 JSON 직렬화 저장/조회. 제네릭 `T` 로 키→값 타입 매핑.
37
+
38
+ - `set<K>(key, value)` — `"{clientName}.{key}"` 키에 `JSON.stringify` 저장.
39
+ - `get<K>(key): T[K] | undefined` — 저장값 파싱. 없거나 파싱 실패 시 `undefined`(결측 보존).
40
+ - `remove(key)` — 키 삭제.
40
41
 
41
- - `set<K extends keyof T & string>(key: K, value: T[K]): void` — `JSON.stringify` 후 저장.
42
- - `get<K extends keyof T & string>(key: K): T[K] | undefined` — 파싱해 반환. 미존재·파싱실패 시 `undefined`(결측 보존).
43
- - `remove(key: keyof T & string): void` — 삭제.
44
- - 사용: `inject<SdLocalStorageProvider<{ "last-tab": string }>>(SdLocalStorageProvider)`.
42
+ ```ts
43
+ private readonly _ls = inject<SdLocalStorageProvider<{ lastTab: string }>>(SdLocalStorageProvider);
44
+ this._ls.set("lastTab", "summary");
45
+ ```
45
46
 
46
47
  ## SdSystemConfigProvider<T>
47
48
 
48
- 화면별 설정(시트 컬럼 구성, 모달 위치 등) 영속화. 외부 저장 함수(`fn`) 꽂혀 있으면 그쪽, 없으면 `SdLocalStorageProvider` 로 폴백.
49
+ 화면별 사용자 설정(시트 컬럼 구성 등) 서버 또는 로컬에 저장/조회. `fn` 미설정 `SdLocalStorageProvider` 로 폴백.
49
50
 
50
- - `fn?: { set(key, data): Promise<void>|void; get(key): PromiseLike<unknown> }` — 서버 등 외부 저장소 연동 훅. 부트스트랩에서 할당하면 모든 설정이 외부로 영속. 미할당이면 로컬스토리지만 사용.
51
- - `setAsync<K>(key: K, data: T[K] | undefined): Promise<void>` — `fn` 있으면 위임, 없으면 로컬스토리지에 저장(데이터 `null` 이면 remove).
52
- - `getAsync(key): Promise<unknown>` `fn` 있으면 위임, 없으면 로컬스토리지 get.
53
- - 직접 호출보다 `injectSdSystemConfigResource` (아래) 로 컴포넌트별 자동 키 분리·resource 화해 쓰는 게 표준.
51
+ - `fn?: { set(key, data); get(key) }` — 외부 저장 콜백. 설정하면 서버 등에 위임, 미설정 로컬스토리지 사용.
52
+ - `setAsync<K>(key, data)` — `data` null 이면 삭제, 아니면 저장.
53
+ - `getAsync(key)`저장값 조회.
54
54
 
55
55
  ## injectSdSystemConfigResource<T>
56
56
 
57
- ```ts
58
- function injectSdSystemConfigResource<T>(options: { key: Signal<string | undefined> }): {
59
- value: Signal<T | undefined>;
60
- isLoading: Signal<boolean>;
61
- status: Signal<...>;
62
- hasValue(): boolean;
63
- reload(): void;
64
- set(value: T | undefined): void;
65
- update(fn: (prev: T | undefined) => T | undefined): void;
66
- }
67
- ```
57
+ `SdSystemConfigProvider` 를 host 태그명+key 로 감싼 Angular `resource` 래퍼. 시트가 컬럼 구성 영속화에 사용. injection 컨텍스트에서 호출.
68
58
 
69
- `SdSystemConfigProvider` 위에 Angular `resource` 얹은 컴포넌트 스코프 헬퍼. 실제 저장 키는 `<호스트엘리먼트태그>.<key>` 자동 분리되어 같은 컴포넌트 종류끼리 설정을 공유.
70
-
71
- - `options.key: Signal<string | undefined>` — 설정 키 signal. `undefined` 면 로드/저장 스킵. 컴포넌트의 `key` 입력을 그대로 넘김.
72
- - `set` — 메모리 즉시 반영 후 microtask 로 `setAsync` 영속(실패 시 ErrorHandler 로 전파, silent skip 아님).
73
- - `sd-sheet` 가 컬럼 설정을 이걸로 보관(sheet.md 참조).
59
+ - `options.key: Signal<string | undefined>` 설정 식별 시그널. `undefined` 로드/저장 함. 저장 키는 `"{호스트태그}.{key}"`.
60
+ - 반환: `value`/`isLoading`/`status`/`hasValue()`/`reload()` 와, 값을 set 하면 즉시 `setAsync` 로 영속하는 `set(value)`·`update(fn)`.
74
61
 
75
62
  ## SdSystemLogProvider
76
63
 
77
- 프레임워크가 잡은 에러/경고를 콘솔 + (배선 ) 외부 저장소로 적재. 자세한 배선·자동 적재 지점은 `client-system-log.md` 참조.
64
+ 콘솔 로깅 + 외부(DB ) 적재를 겸하는 시스템 로그 프로바이더. 전역 에러 핸들러가 이걸로 에러를 기록.
78
65
 
79
- - `writeFn?: (severity: "error"|"warn"|"log", ...data: any[]) => Promise<void>|void` — 외부 적재 함수. 부트스트랩에서 1회 할당(예: DB insert). 미할당 시 콘솔만.
80
- - `writeAsync(severity: "error"|"warn"|"log", ...data: any[]): Promise<void>` 항상 콘솔(`createLogger("angular:system-log")`)먼저 찍고, `writeFn` 있으면 추가 적재. `writeFn` 호출은 try/catch 로 감싸 실패해도 throw 하지 않음(로그 싱크 실패가 본 동작을 막지 않게 한 의도된 설계).
81
- - `severity` 값 차이: `"error"` = 문제 발생, `"warn"` = 인지 필요, `"log"` = 일반. `SdGlobalErrorHandlerPlugin`·`SdToastProvider.try/danger` 가 자동으로 `"error"` 적재.
82
- - 직접 적재: `await this._sdSystemLog.writeAsync("error", "결제 승인 실패", err.stack)`.
66
+ - `writeFn?: (severity: "error"|"warn"|"log", ...data) => Promise<void>|void` — 외부 적재 콜백. 설정 콘솔 출력 후 호출(실패해도 throw 안 하고 logger.error).
67
+ - `writeAsync(severity, ...data)`콘솔에 해당 severity 출력하고, `writeFn` 있으면 함께 적재.
68
+
69
+ ```ts
70
+ const sysLog = inject(SdSystemLogProvider);
71
+ sysLog.writeFn = (sev, ...data) => appService.systemLog.writeAsync(sev, data);
72
+ ```
83
73
 
84
74
  ## SdServiceClientFactoryProvider
85
75
 
86
- `@simplysm/service-client` `ServiceClient` 를 key 별로 생성·보관·종료. 요청/응답 진행률을 자동으로 토스트 progress 로 표시.
76
+ 키별로 `ServiceClient`(`@simplysm/service-client`) 연결을 생성·보관·종료하고, 요청/응답 진행률을 토스트로 표시.
77
+
78
+ - `connectAsync(key, options?)` — 현재 location(host/port/ssl) 기본값에 `options` 머지해 연결. 이미 연결/종료된 키면 throw. 진행 이벤트를 progress 토스트로.
79
+ - `closeAsync(key)` — 해당 키 연결 종료. 미연결 키면 throw.
80
+ - `get(key): ServiceClient` — 연결된 클라이언트 반환. 미연결/종료 키면 throw.
87
81
 
88
- - `connectAsync(key: string, options?: Partial<ServiceConnectionOptions>): Promise<void>` — key 로 클라이언트 연결. host/port/ssl 미지정 시 현재 `location` 기준 기본값. 이미 연결됐거나 닫힌 key throw. 연결 `request-progress`/`response-progress` 를 받아 `SdToastProvider.info(..., true)` progress 로 갱신.
89
- - `closeAsync(key: string): Promise<void>` — 연결 종료 + 해당 key 를 닫힘 처리(재연결 불가). 미연결 key 면 throw.
90
- - `get(key: string): ServiceClient` — 연결된 클라이언트 반환. 미연결/닫힘이면 throw(silent 반환 안 함).
91
- - 앱은 보통 `AppServiceProvider` 가 이걸 래핑(`client-service.md`). 화면에서 직접 inject 하기보다 앱 provider 경유.
82
+ 서비스 프로바이더(`AppServiceProvider`)가 팩토리를 감싸 쓰는 형태이며, 직접 호출보다 프로바이더 경유가 일반적.
@@ -1,63 +1,53 @@
1
- # @simplysm/angular — 레이아웃(사이드바·탑바)
1
+ # @simplysm/angular — 레이아웃(사이드바·탑바)
2
2
 
3
3
  앱 셸의 좌측 사이드바·상단바와 그 안의 메뉴/사용자 메뉴 컴포넌트 군. 앱 루트 레이아웃(`app.root` 등)에서 한 번 구성. 메뉴 항목 타입(`SdMenu`)·라우터 링크는 routing-appstructure.md 의 것을 사용.
4
4
 
5
5
  ## 사이드바
6
6
 
7
- ### SdSidebarContainer (`sd-sidebar-container`)
7
+ ### SdSidebarContainer `sd-sidebar-container`
8
+ 사이드바 + 본문을 감싸는 컨테이너. 토글 시 본문 패딩을 조정하고 모바일에서 backdrop 표시. 라우팅 시작 시 자동 닫힘. 입력 없음(내부 `toggle` 상태 보유).
8
9
 
9
- 사이드바 + 본문을 감싸는 컨테이너. 데스크톱은 사이드바 폭만큼 좌패딩, 모바일은 오버레이. 라우팅 시작 시 자동으로 토글을 닫음(모바일 메뉴 닫힘).
10
+ ### SdSidebar `sd-sidebar`
11
+ 실제 사이드바 패널. 부모 컨테이너의 `toggle` 을 따라 슬라이드. 입력 없음. 자식으로 메뉴/유저 메뉴 배치.
10
12
 
11
- - `toggle: WritableSignal<boolean>` 사이드바 접힘(데스크톱) / 닫힘(모바일) 상태. `sd-topbar` 의 햄버거가 이걸 토글. 배경(backdrop) 클릭으로도 토글.
12
- - 자식으로 `<sd-sidebar>` 와 본문을 둠.
13
+ ### SdSidebarMenu — `sd-sidebar-menu`
14
+ 메뉴 트리를 리스트로 렌더.
15
+ - `menus: input<SdMenu[]>` — 표시할 메뉴 트리(보통 `appStructure.usableMenus()`).
16
+ - `layout: "accordion"|"flat"` — 펼침 방식. 미지정 시 루트 메뉴 3개 이하면 `"flat"`, 초과면 `"accordion"` 자동.
17
+ - `getMenuIsSelectedFn: (menu) => boolean` — 선택 판정 커스텀(미지정 시 현재 페이지 코드 일치).
13
18
 
14
- ### SdSidebar (`sd-sidebar`)
19
+ ### SdSidebarUser `sd-sidebar-user`
20
+ 사이드바 상단 사용자 영역(이름 + 펼침 메뉴).
21
+ - `userMenu: input<SdSidebarUserMenu>` — `{ icon?, title, menus: { title, onClick }[] }`. `title` 이 사용자명, `menus` 가 펼침 항목(로그아웃 등).
15
22
 
16
- 실제 사이드바 패널. 부모 `SdSidebarContainer.toggle` 에 따라 슬라이드 인/아웃.
17
-
18
- - (입력 없음) 부모 컨테이너의 toggle 을 computed 로 반영. 내부에 `<sd-sidebar-user>`·`<sd-sidebar-menu>` 등을 배치.
19
-
20
- ### SdSidebarMenu (`sd-sidebar-menu`)
21
-
22
- 메뉴 트리를 리스트로 렌더(중첩, 라우터 링크/외부 URL).
23
-
24
- - `menus: SdMenu[]` — 표시할 메뉴 트리(보통 `SdAppStructureProvider.usableMenus()`).
25
- - `layout: "accordion"|"flat"` — 루트 레벨 레이아웃. 미지정 시 메뉴 3개 이하면 `"flat"`, 초과면 `"accordion"` 자동 선택.
26
- - `getMenuIsSelectedFn: (menu: SdMenu) => boolean` — 선택 판정 커스텀(미지정 시 현재 페이지 코드 비교).
27
- - 동작: leaf 메뉴는 `getMenuRouterLinkOption` 으로 라우팅, `url` 메뉴는 새 창.
28
-
29
- ### SdSidebarUser (`sd-sidebar-user`)
30
-
31
- 사이드바 상단 사용자 영역 + 접이식 사용자 메뉴.
32
-
33
- - `userMenu: SdSidebarUserMenu` — `{ title: string; menus: { title: string; onClick: () => void }[] }`. `title` 클릭 시 메뉴 펼침, 각 메뉴 클릭 시 `onClick`. 로그아웃/설정 등.
34
- - `<ng-content>` 로 사용자 이름/아바타 영역 배치.
23
+ ```html
24
+ <sd-sidebar-container>
25
+ <sd-sidebar>
26
+ <sd-sidebar-user [userMenu]="{ title: userName(), menus: [{ title: '로그아웃', onClick: logout }] }" />
27
+ <sd-sidebar-menu [menus]="menus()" />
28
+ </sd-sidebar>
29
+ <router-outlet />
30
+ </sd-sidebar-container>
31
+ ```
35
32
 
36
33
  ## 탑바
37
34
 
38
- ### SdTopbarContainer (`sd-topbar-container`)
39
-
40
- 상단바 + 본문 세로 스택 컨테이너(상단 고정 + 본문 fill). `sd-base-container` 가 page 모드에서 내부적으로 사용.
41
-
42
- ### SdTopbar (`sd-topbar`)
43
-
44
- 상단바 본문. 사이드바가 있으면 좌측에 햄버거 토글 버튼 자동 표시.
45
-
46
- - `sidebarContainer: SdSidebarContainer` — 토글 대상 사이드바 컨테이너(미지정 시 inject 로 자동 탐색). 둘 다 없으면 햄버거 미표시.
47
- - `hasSidebar: Signal<boolean>` — 사이드바 존재 여부(햄버거 표시 기준).
48
- - `<ng-content>` 로 제목·메뉴·사용자 영역 배치.
49
-
50
- ### SdTopbarMenu (`sd-topbar-menu`)
51
-
52
- 상단바 가로 메뉴(드롭다운 펼침).
35
+ ### SdTopbarContainer `sd-topbar-container`
36
+ 탑바 + 본문 세로 컨테이너. 입력 없음. (`sd-base-container` 가 page 모드에서 내부적으로 사용.)
53
37
 
54
- - `menus: SdMenu[]` 표시할 메뉴 트리. 각 루트 메뉴가 드롭다운 버튼이 되고 children 을 팝업 리스트로.
55
- - `getMenuIsSelectedFn: (menu: SdMenu) => boolean` — 선택 판정 커스텀.
56
- - leaf 클릭라우팅 + 드롭다운 닫힘, `url` 메뉴는 창.
38
+ ### SdTopbar`sd-topbar`
39
+ 상단바. 사이드바 토글 버튼 + 타이틀/명령 슬롯.
40
+ - `sidebarContainer: input<SdSidebarContainer>` — 토글 대상 사이드바 컨테이너(미지정 inject 상위 컨테이너 사용). 하나라도 있으면 토글 버튼 노출.
57
41
 
58
- ### SdTopbarUser (`sd-topbar-user`)
42
+ ### SdTopbarMenu `sd-topbar-menu`
43
+ 상단 가로 메뉴.
44
+ - `menus: input<SdMenu[]>` — 메뉴 항목.
45
+ - `getMenuIsSelectedFn: (menu) => boolean` — 선택 판정 커스텀.
59
46
 
60
- 상단바 우측 사용자 드롭다운 메뉴.
47
+ ### SdTopbarUser `sd-topbar-user`
48
+ 상단 우측 사용자 드롭다운.
49
+ - `menus: input.required<SdTopbarUserMenu[]>` — `{ title, onClick }[]`. 클릭 시 `onClick` 실행 후 드롭다운 닫힘.
61
50
 
62
- - `menus: input.required<SdTopbarUserMenu[]>` — `SdTopbarUserMenu = { title: string; onClick: () => void }`. 각 항목 클릭 시 `onClick` 실행 후 드롭다운 닫힘.
63
- - `<ng-content>` 트리거 버튼 라벨(사용자 이름) 배치.
51
+ ### 타입
52
+ - `SdSidebarUserMenu` `{ icon?: string; title: string; menus: { title: string; onClick: () => Promise<void>|void }[] }`.
53
+ - `SdTopbarUserMenu` — `{ title: string; onClick: () => void }`.
@@ -1,103 +1,111 @@
1
- # @simplysm/angular — 모달·토스트·Busy·인쇄 (오버레이/전역 피드백)
1
+ # @simplysm/angular — 오버레이(모달·토스트·busy·인쇄)
2
2
 
3
- 화면에서 프로그래밍 방식으로 모달을 띄우거나, 토스트로 알림·진행률을 표시하거나, busy 인디케이터·인쇄/PDF 출력을 호출할 때 함께 읽히는 군. provider 는 모두 `providedIn: "root"`, 컴포넌트는 provider 가 동적으로 body 에 attach 하므로 템플릿에 직접 둘 일은 거의 없음.
3
+ 화면에서 프로그래밍 방식으로 모달을 띄우거나, 토스트로 알림·진행률을 표시하거나, busy 인디케이터·인쇄/PDF 출력을 호출할 때 함께 읽히는 군. provider 는 모두 `providedIn: "root"`, 동적으로 body 에 attach 하므로 컴포넌트를 템플릿에 직접 둘 일은 거의 없음.
4
4
 
5
5
  ## SdModalProvider
6
6
 
7
- 컴포넌트를 모달 셸(`SdModal`) 안에 동적 생성해 body 띄움. `close.emit(payload)` 또는 닫기(X/배경/ESC)로 종료.
7
+ `showAsync` 컴포넌트를 모달로 띄움. 컨텐츠 컴포넌트는 `SdModalContentDef<O>` 구현해야 함.
8
8
 
9
- ```ts
10
- showAsync<T extends SdModalContentDef<any>>(
11
- modal: SdModalInfo<T>, options?: SdModalOptions,
12
- ): Promise<Parameters<T["close"]["emit"]>[0] | undefined>
13
- ```
14
-
15
- - `modal.type: Type<T>` — `SdModalContentDef<O>` 를 구현한 컴포넌트 클래스(`SdModal` 자체가 아님). `O` 가 close 페이로드 타입.
16
- - `modal.title: string` — 모달 헤더 제목.
17
- - `modal.inputs` — 모달 컴포넌트가 받을 input 값. `initialized`/`close`/`actionTplRef` 와 `_optionalModalInputs` 로 표시된 키는 제외/optional 처리됨. 없으면 `{}`.
18
- - 반환값 — 컴포넌트가 `close.emit` 한 페이로드. 닫기/취소로 닫히면 `undefined`. 매뉴얼 패턴: `const r = await this._sdModal.showAsync({...}); if (!r) return;`.
19
9
  - `modalCount: WritableSignal<number>` — 현재 열린 모달 수.
10
+ - `showAsync<T>(modal: SdModalInfo<T>, options?: SdModalOptions): Promise<O | undefined>` — 모달을 띄우고 close 페이로드를 반환. 사용자가 X/취소로 닫으면 `undefined`.
11
+
12
+ `SdModalInfo<T>`:
13
+ - `title: string` — 모달 헤더 제목.
14
+ - `type: Type<T>` — `SdModalContentDef` 구현 컴포넌트 클래스.
15
+ - `inputs` — 컴포넌트 input 값들. `initialized`/`close`/`actionTplRef` 제외, optional 입력은 생략 가능.
16
+
17
+ `SdModalContentDef<O>` (컨텐츠 컴포넌트가 구현):
18
+ - `initialized: Signal<boolean>` — 로드 완료 시그널.
19
+ - `close: OutputEmitterRef<O | undefined>` — 닫기 + 페이로드 emit. emit 값이 `showAsync` 반환값.
20
+ - `actionTplRef?: TemplateRef` — 헤더 우측에 끼울 액션 영역 템플릿(선택).
21
+
22
+ `SdModalOptions` (선택):
23
+ - `key?: string` — 모달 식별 키.
24
+ - `hideHeader: boolean` — 헤더 숨김. true 면 제목/닫기 영역 없음.
25
+ - `hideCloseButton: boolean` — 닫기 버튼만 숨김.
26
+ - `headerStyle?: string` — 헤더 인라인 스타일.
27
+ - `useCloseByBackdrop: boolean` — 배경 클릭으로 닫기 허용(기본 true).
28
+ - `useCloseByEscapeKey: boolean` — ESC 로 닫기 허용(기본 true).
29
+ - `float: boolean` — 화면에 띄우는 플로팅 모드.
30
+ - `fill: boolean` — 화면 가득 채움.
31
+ - `resizable: boolean` — 가장자리 드래그 리사이즈 허용.
32
+ - `movable: boolean` — 헤더 드래그 이동 허용.
33
+ - `position: "bottom-right"|"top-right"` — 고정 위치.
34
+ - `minHeightPx`/`minWidthPx`/`heightPx`/`widthPx: number` — 크기(px).
35
+ - `noFirstControlFocusing: boolean` — true 면 첫 입력에 자동 포커스하지 않고 dialog 에 포커스.
20
36
 
21
- ### SdModalContentDef<O> (모달 컴포넌트가 구현)
22
-
23
- - `initialized: Signal<boolean>` 초기화 완료 여부. busy 표시 해제 기준.
24
- - `close: OutputEmitterRef<O | undefined>` — 결과 emit. `O` 가 `showAsync` 반환 타입.
25
- - `actionTplRef?: TemplateRef<any>` — 헤더 우측에 끼울 액션 영역 템플릿(있으면 모달 헤더로 브릿지됨).
26
- - `_optionalModalInputs?: string` — (타입 전용 마커) 이 컴포넌트의 input 중 optional 로 둘 키 이름 리터럴. 런타임 값 아님.
27
-
28
- ### SdModalOptions (showAsync 2번째 인자)
29
-
30
- - `key?: string` — 설정 저장 키. 지정 시 사용자가 조정한 width/height/위치를 `SdSystemConfigProvider` 에 영속·복원.
31
- - `hideHeader?: boolean` — true 면 제목/닫기 헤더 숨김. 헤더 없는 풀커스텀 모달용.
32
- - `hideCloseButton?: boolean` — true 면 헤더 X 버튼만 숨김.
33
- - `headerStyle?: string` — 헤더 영역 인라인 스타일.
34
- - `useCloseByBackdrop?: boolean` — 배경 클릭으로 닫기 허용(기본 동작상 컴포넌트 기본 true). false 면 배경 클릭 무시.
35
- - `useCloseByEscapeKey?: boolean` — ESC 로 닫기 허용. false 면 ESC 무시.
36
- - `float?: boolean` — true 면 배경(backdrop) 없는 떠있는 패널. 비모달 보조 패널용.
37
- - `fill?: boolean` — true 면 화면 전체를 채움(풀스크린 모달).
38
- - `resizable?: boolean` — true 면 8방향 리사이즈 핸들 표시.
39
- - `movable?: boolean` — true 면 헤더 드래그로 이동.
40
- - `position?: "bottom-right" | "top-right"` — 고정 위치. 토스트성 알림 모달에 사용.
41
- - `minHeightPx?/minWidthPx?/heightPx?/widthPx?: number` — 최소/초기 크기.
42
- - `noFirstControlFocusing?: boolean` — true 면 첫 입력 요소 자동 포커스를 끔(다이얼로그 자체에 포커스).
37
+ ```ts
38
+ const result = await inject(SdModalProvider).showAsync(
39
+ { type: GoodsDetailModal, title: "품목 등록", inputs: { goodsId: 12 } },
40
+ { resizable: true, widthPx: 720 },
41
+ );
42
+ if (result == null) return;
43
+ ```
43
44
 
44
- ### 내장 모달 컴포넌트
45
+ ## SdActivatedModalProvider<T>
45
46
 
46
- - `SdPromptModal` (`SdModalContentDef<string>`) 메시지 + 텍스트 입력 확인/취소. `message: input.required<string>` (innerHTML). 확인 시 입력값, 취소/닫기 시 `undefined`. 입력은 required 빈 값이면 네이티브 검증으로 차단.
47
- - `SdConfirmModal` (`SdModalContentDef<boolean>`) — 메시지 + 확인/취소. `message: input.required<string>`. 확인 시 `true`, 취소/닫기 시 `undefined`.
48
- - 사용: `const ok = await this._sdModal.showAsync({ type: SdConfirmModal, title: "확인", inputs: { message: "삭제할까요?" } }); if (!ok) return;`.
47
+ 모달 컨텐츠 컴포넌트 안에서 inject 자기 모달 셸을 제어. `SdModalProvider` 컨텐츠 인젝터에 주입.
49
48
 
50
- ### SdActivatedModalProvider
49
+ - `modalComponent: WritableSignal<SdModal | undefined>` — 모달 셸 컴포넌트 참조(제목 등 조회).
50
+ - `contentComponent: WritableSignal<T | undefined>` — 컨텐츠 컴포넌트 참조.
51
+ - `canDeactivateFn: () => boolean` — 닫기 시도 시 가드. `setupCanDeactivate` 가 이 값을 설정.
51
52
 
52
- 모달 컴포넌트 내부에서 inject. 자기 모달의 셸/콘텐츠 참조와 이탈 가드를 보유.
53
+ ## SdPromptModal / SdConfirmModal
53
54
 
54
- - `modalComponent: Signal<SdModal | undefined>` / `contentComponent: Signal<T | undefined>` — 셸/콘텐츠 컴포넌트 참조.
55
- - `canDeactivateFn: () => boolean` — 닫기 시도 시 false 면 닫힘 차단. `setupCanDeactivate`(routing-appstructure.md) 가 모달 컨텍스트에서 이걸 설정.
55
+ 바로 쓰는 범용 모달 컨텐츠 컴포넌트.
56
56
 
57
- ### SdModal (모달 셸)
57
+ - `SdPromptModal` — `SdModalContentDef<string>`. `message: input.required<string>` 를 표시하고 텍스트 입력(필수) 후 확인 시 입력값, 취소 시 `undefined` emit.
58
+ - `SdConfirmModal` — `SdModalContentDef<boolean>`. `message: input.required<string>` 표시 후 확인 시 `true`, 취소 시 `undefined` emit.
58
59
 
59
- `SdModalProvider` 가 내부적으로 생성하는 셸 컴포넌트. 상속·직접 배치 대상 아님. `<ng-content>` 로 콘텐츠를 투영하고 위 `SdModalOptions` 와 동일한 input(`title`/`open`/`resizable`/... `closeRequest` output) 을 보유.
60
+ ```ts
61
+ const ok = await sdModal.showAsync({ type: SdConfirmModal, title: "삭제", inputs: { message: "삭제할까요?" } });
62
+ ```
60
63
 
61
64
  ## SdToastProvider
62
65
 
63
- 화면 우상단(또는 overlap 모드)에 토스트를 띄움. 알림·비동기 에러 가드·진행률에 사용.
66
+ 토스트 알림·진행률·커스텀 토스트를 띄우고, 비동기 try 래퍼를 제공.
64
67
 
65
- - `info/success/warning/danger(message: string): void` — 심각도별 토스트 1개 표시(3초 자동 해제, hover 중이면 지연). `info`/`success` `aria-live=polite`, `warning`/`danger` `assertive`. 심각도 의미는 `sd-design-rules` 분류를 따름(error=문제 발생).
66
- - `info/...(message: string, useProgress: true): WritableSignal<number>` — progress 모드. 반환된 signal 0~100 set 하면 진행바 갱신, 100 도달 1초 자동 해제. 업로드/다운로드 진행률 표시에 사용.
67
- - `try<R>(fn: () => Promise<R> | R, messageFn?: (err: Error) => string): Promise<R | undefined>` — `fn` 실행 중 `Error` throw 되면 잡아서 `danger` 토스트 + 시스템로그 `error` 적재 후 `undefined` 반환(에러를 외부로 전파하지 않음). `Error` 가 아닌 throw 는 그대로 재전파. 매뉴얼의 비동기 작업 표준 가드: `await this._sdToast.try(async () => { ... })`.
68
- - `notify<T extends SdToastContentDef<any>>(input: SdToastInput<T>): Promise<...>` 커스텀 컴포넌트를 토스트로 띄우고 `close` 페이로드를 반환(5초 후 자동 `undefined`).
69
- - `alertThemes: WritableSignal<SdToastSeverity[]>` — 여기 심각도는 토스트 대신 `window.alert` 표시(키오스크 등 강제 확인 필요 화면).
70
- - `overlap: WritableSignal<boolean>` true 토스트가 기존 토스트를 제거하고 단독 표시.
71
- - `beforeShowFn?: (theme: SdToastSeverity) => void` — 토스트 표시 직전 콜백(사운드 등).
68
+ - `info`/`success`/`warning`/`danger(message, useProgress?)` — 해당 severity 토스트. `useProgress: true` 진행률 토스트로 `WritableSignal<number>`(0~100) 반환(100 도달 1초 자동 닫힘), `false`/생략이면 일정 시간 자동 닫힘.
69
+ - `try<R>(fn, messageFn?): Promise<R | undefined>` — `fn` 실행 `Error` throw `danger` 토스트로 표시하고 시스템 로그에 기록한 `undefined` 반환(에러 throw 재전파). 화면 비동기 작업 표준 래퍼.
70
+ - `notify<T>(input: SdToastInput<T>): Promise<O | undefined>` — 커스텀 컴포넌트(`SdToastContentDef<O>`)를 토스트로 띄움. close emit 또는 5초 후 `undefined` 반환.
71
+ - `alertThemes: WritableSignal<SdToastSeverity[]>`여기에 severity 토스트 대신 `window.alert` 표시.
72
+ - `overlap: WritableSignal<boolean>` — true 토스트가 기존 토스트를 모두 치움.
73
+ - `beforeShowFn?: (theme) => void` 토스트 표시 직전 콜백.
72
74
 
73
75
  타입:
74
-
75
76
  - `SdToastSeverity = "info"|"success"|"warning"|"danger"`.
76
- - `SdToastTheme = "primary"|"secondary"|SdToastSeverity|"gray"|"blue-gray"` — `sd-toast` 컴포넌트 `theme` 입력 범위.
77
- - `SdToastContentDef<O> = { close: OutputEmitterRef<O | undefined> }` — `notify` 커스텀 컴포넌트 규약.
78
- - `SdToastInput<T> = { type: Type<T>; inputs: Omit<DirectiveInputSignals<T>, "close"> }`.
77
+ - `SdToastTheme = "primary"|"secondary"|SdToastSeverity|"gray"|"blue-gray"`.
78
+ - `SdToastContentDef<O>` `close: OutputEmitterRef<O | undefined>` 보유.
79
+ - `SdToastInput<T>` `{ type: Type<T>; inputs }`(`close` 제외).
80
+
81
+ ```ts
82
+ this.busyCount.update((v) => v + 1);
83
+ await this._sdToast.try(async () => { await this._refresh(); });
84
+ this.busyCount.update((v) => v - 1);
85
+ this._sdToast.success("저장되었습니다.");
86
+ ```
79
87
 
80
- `SdToast`/`SdToastContainer` 는 provider 가 동적 생성하는 표시 컴포넌트(직접 배치 불필요).
88
+ ## SdBusyProvider
81
89
 
82
- ## SdBusyProvider / SdBusyContainer
90
+ 전역 busy 인디케이터 상태. `provideSdAngular` 가 라우팅 동안 증감, 인쇄 provider 도 사용.
83
91
 
84
- 영역 단위 busy 오버레이.
92
+ - `type: WritableSignal<SdBusyType>` — 인디케이터 모양(`"spinner"|"bar"|"cube"`, 기본 `"bar"`).
93
+ - `globalBusyCount: WritableSignal<number>` — 0 보다 크면 화면 전체 busy 오버레이 표시. 비동기 작업 시작 `+1`, 종료 `-1`.
85
94
 
86
- - `SdBusyProvider.type: WritableSignal<SdBusyType>` 전역 기본 인디케이터 종류. `SdBusyType = "spinner"|"bar"|"cube"`. `"bar"` = 상단 가는 진행바, `"spinner"` = 회전 원, `"cube"` = 큐브 애니메이션.
87
- - `SdBusyProvider.globalBusyCount: WritableSignal<number>` — 전역 busy 카운트(>0 이면 화면 전체 busy). 라우팅·인쇄가 ±1. 직접 ±1 해 전역 차단 가능.
88
- - `SdBusyContainer` (`sd-busy-container`) — 자식 영역에 busy 오버레이를 씌우는 컨테이너 컴포넌트.
89
- - `busy: boolean` — true 면 오버레이 표시 + 영역 내 키입력 차단.
90
- - `message: string` — 인디케이터 옆/아래 표시 메시지.
91
- - `type: SdBusyType` — 이 영역만의 인디케이터 종류(미지정 시 provider 기본값).
92
- - `progressPercent: number` — 지정 시 상단 진행바(0~100). 결정형 작업 진행률에 사용.
93
- - 사용: `<sd-busy-container [busy]="busyCount() > 0">...</sd-busy-container>` (단, `sd-base-container` 가 이미 내장).
95
+ `SdBusyContainer` 컴포넌트(영역 단위 busy): `busy: boolean`, `message?: string`, `type?: SdBusyType`, `progressPercent?: number`(진행 바). 화면 영역을 감싸 영역만 busy 표시.
94
96
 
95
97
  ## SdPrintProvider
96
98
 
97
- 인쇄 템플릿 컴포넌트를 동적 생성해 `window.print()` 하거나 PDF 버퍼로 변환. 호출 동안 `globalBusyCount` ±1.
99
+ 화면 컴포넌트(`SdPrint` 구현)를 인쇄하거나 PDF 버퍼로 변환. 처리 동안 `globalBusyCount` 증감.
98
100
 
99
- - `printAsync<T extends SdPrint>(template: SdPrintInput<T>, options?: { size?: string; margin?: string }): Promise<void>` — 템플릿을 숨겨 붙인 뒤 `@media print` CSS 그것만 출력. `size` 기본 `"A4 auto"`, `margin` 기본 `"0"`. 이미지 로드 완료를 기다린 후 인쇄.
100
- - `getPdfBufferAsync<T extends SdPrint>(template: SdPrintInput<T>, options?: { orientation?: "portrait"|"landscape"; pageSize?: string }): Promise<Uint8Array>` — `.page` 요소들(없으면 루트) 캔버스로 렌더해 jsPDF 로 PDF 바이트 생성. `orientation` 기본 portrait, `pageSize` 기본 `"a4"`. 첨부/저장용 PDF 가 필요할 때.
101
- - `SdPrint = { initialized: Signal<boolean>; _optionalPrintInputs?: string }` — 인쇄 템플릿 컴포넌트 규약. `initialized` 가 true 가 되어야 인쇄 진행(데이터 로드 대기).
102
- - `SdPrintInput<T> = { type: Type<T>; inputs: ... }` — 인쇄 컴포넌트 + input 값(`_optionalPrintInputs` 표시 키는 optional).
103
- - 사용: `await this._sdPrint.printAsync({ type: OutboundPrintTemplate, inputs: { id } })`. 인쇄 템플릿 파일은 `<domain>.print-template.ts`(client-component.md).
101
+ - `printAsync<T>(template: SdPrintInput<T>, options?: { size?: string; margin?: string }): Promise<void>` — 컴포넌트를 렌더해 `@page` 스타일을 걸고 `window.print` 호출. `initialized()` 이미지 로드를 대기.
102
+ - `getPdfBufferAsync<T>(template, options?: { orientation?: "portrait"|"landscape"; pageSize?: string }): Promise<Uint8Array>` — `.page` 요소(없으면 전체) 캔버스로 jsPDF 로 PDF 바이트 생성.
103
+
104
+ `SdPrint` (템플릿 컴포넌트가 구현): `initialized: Signal<boolean>`(렌더 완료 시그널). `SdPrintInput<T>` `{ type: Type<T>; inputs }`.
105
+
106
+ ```ts
107
+ await inject(SdPrintProvider).printAsync(
108
+ { type: InvoicePrintTemplate, inputs: { invoiceId: 5 } },
109
+ { size: "A4", margin: "10mm" },
110
+ );
111
+ ```