@simplysm/sd-claude 14.0.89 → 14.0.90

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 (79) hide show
  1. package/claude/references/sd-simplysm14/README.md +16 -17
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +52 -30
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +200 -38
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -53
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +66 -22
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +127 -40
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +60 -43
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +56 -20
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +74 -74
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +50 -40
  11. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -15
  12. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +59 -42
  13. package/claude/references/sd-simplysm14/apis/angular/sheet.md +77 -62
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +8 -7
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +22 -14
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +19 -19
  18. package/claude/references/sd-simplysm14/apis/core-browser/README.md +17 -17
  19. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +28 -28
  20. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +37 -37
  21. package/claude/references/sd-simplysm14/apis/core-common/README.md +87 -219
  22. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +54 -98
  23. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +57 -99
  24. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +60 -103
  25. package/claude/references/sd-simplysm14/apis/core-common/errors.md +42 -47
  26. package/claude/references/sd-simplysm14/apis/core-common/obj.md +42 -88
  27. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
  28. package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -7
  29. package/claude/references/sd-simplysm14/apis/core-node/consola.md +17 -12
  30. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +14 -13
  31. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +9 -8
  32. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +14 -13
  33. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +4 -8
  34. package/claude/references/sd-simplysm14/apis/core-node/worker.md +14 -12
  35. package/claude/references/sd-simplysm14/apis/excel/README.md +22 -22
  36. package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
  37. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
  38. package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
  39. package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
  40. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
  41. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
  42. package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -8
  43. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +118 -67
  44. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +83 -86
  45. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +102 -93
  46. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +138 -81
  47. package/claude/references/sd-simplysm14/apis/orm-common/types.md +49 -44
  48. package/claude/references/sd-simplysm14/apis/orm-node/README.md +42 -42
  49. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +44 -33
  50. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +11 -10
  51. package/claude/references/sd-simplysm14/apis/service-client/README.md +56 -52
  52. package/claude/references/sd-simplysm14/apis/service-client/orm.md +33 -28
  53. package/claude/references/sd-simplysm14/apis/service-client/transport.md +23 -21
  54. package/claude/references/sd-simplysm14/apis/service-common/README.md +83 -48
  55. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
  56. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
  57. package/claude/references/sd-simplysm14/apis/service-server/README.md +69 -81
  58. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +46 -43
  59. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +63 -37
  60. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +40 -30
  61. package/claude/references/sd-simplysm14/apis/storage/README.md +17 -17
  62. package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
  63. package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
  64. package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
  65. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
  66. package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
  67. package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
  68. package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
  69. package/claude/rules/sd-design-rules.md +10 -0
  70. package/claude/skills/sd-demo/SKILL.md +0 -6
  71. package/claude/skills/sd-docs/SKILL.md +58 -0
  72. package/claude/{workflows/sd-docs.rules.md → skills/sd-docs/references/subagent-prompt.md} +103 -103
  73. package/claude/skills/sd-impl/SKILL.md +7 -4
  74. package/claude/skills/sd-spec/SKILL.md +842 -15
  75. package/claude/skills/sd-spec/references/example-spec.md +26 -36
  76. package/package.json +1 -1
  77. package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -53
  78. package/claude/skills/sd-spec/references/spec-authoring.md +0 -519
  79. package/claude/workflows/sd-docs.js +0 -84
@@ -1,34 +1,78 @@
1
- # @simplysm/angular — 호스트 디렉티브·동작 셋업·템플릿
1
+ # @simplysm/angular — 디렉티브·signal setup 헬퍼
2
2
 
3
- 엘리먼트/컴포넌트에 동작을 부착하는 디렉티브와, 컴포넌트 constructor 에서 호출하는 `setup*` 훅, 타입드 ng-template 묶음. 컴포넌트 동작을 직접 조립할 함께 읽힘.
3
+ DOM 관찰(리사이즈/교차)·캡처 이벤트·커맨드 단축키·ripple·노출 애니메이션·invalid 표시·타입드 템플릿을 호스트 엘리먼트에 붙이는 군. `setup*` 헬퍼는 컴포넌트 `constructor` 안에서 호출(`inject(ElementRef)` 의존), `Sd*` 디렉티브는 헬퍼를 attribute 로 래핑한 것.
4
4
 
5
- ## 이벤트 디렉티브
5
+ ## SdResizeDirective (`[sdResize]`)
6
6
 
7
- 옵션 이벤트(`.capture`/`.passive`/`.once`)는 `provideSdAngular` 등록한 `SdOptionEventPlugin` 으로 동작. 직접 inject 안 함.
7
+ `ResizeObserver` requestAnimationFrame 으로 디바운스해 크기 변화를 emit.
8
8
 
9
- - **SdEvents** — 표준 이벤트의 옵션 변형을 output 으로 노출하는 디렉티브. `(click.capture)`, `(scroll.passive)`, `(touchstart.passive)`, `(wheel.capture.passive)`, `(transitionend.once)` 등(셀렉터에 열거된 조합만). 버블링 안 되는 focus/blur 를 capture 로 받거나 성능상 passive 스크롤이 필요할 때 사용.
10
- - **SdResizeDirective** — `(sdResize)` 출력. ResizeObserver 기반, requestAnimationFrame 디바운스. 이벤트 `SdResizeEvent = { heightChanged; widthChanged; target: HTMLElement; contentRect: DOMRectReadOnly }`. 크기 변화에 반응할 때.
11
- - **SdIntersectionDirective** `(sdIntersection)` 출력. IntersectionObserver 기반. 이벤트 `SdIntersectionEvent = { entry: IntersectionObserverEntry }`. 화면 진입 감지(지연 로드 등)에.
12
- - **SdCommandDirective** — `(sdRefreshCommand)`(Ctrl+Alt+L), `(sdSaveCommand)`(Ctrl+S), `(sdInsertCommand)`(Insert) 출력(`KeyboardEvent`). 최상위로 열린 모달 안에서만 동작(가려진 화면 단축키 차단). 새로고침/저장/추가 단축키 바인딩에.
9
+ - `sdResize: output<SdResizeEvent>` 크기 변화 발화.
10
+ - `SdResizeEvent = { heightChanged: boolean; widthChanged: boolean; target: HTMLElement; contentRect: DOMRectReadOnly }` 어떤 축이 바뀌었는지·대상·새 사각형. `heightChanged`/`widthChanged` 로 필요한 축만 처리.
11
+ - 사용: `<div (sdResize)="onResize($event)">`. `sd-sheet`·`sd-collapse`·`sd-echarts` 등이 hostDirective 사용.
13
12
 
14
- ## 표시 효과 디렉티브 + 셋업 훅
13
+ ## SdIntersectionDirective (`[sdIntersection]`)
15
14
 
16
- - **SdRipple** / **setupRipple** — `[sdRipple]="enabled"` 디렉티브 또는 `setupRipple(enableFn?: () => boolean)` 훅. 포인터 다운 위치에서 퍼지는 물결 효과. enabled/enableFn false 면 비활성. 버튼류에 부착.
17
- - **SdShowEffect** / **setupRevealOnShow** — `[sdShowEffect]="enabled"` + `sdShowEffectType`("l2r"|"t2b", 기본 t2b) 디렉티브, 또는 `setupRevealOnShow(optFn?: () => { type?; enabled? })` 훅. 화면 진입 시 페이드+슬라이드로 나타남. type 은 슬라이드 방향(t2b=위→아래, l2r=왼→오). 진입 애니메이션에.
18
- - **SdInvalid** / **setupInvalid** — `[sdInvalid]="message"` 디렉티브, 또는 `setupInvalid(getInvalidMessage: () => string)` 훅. 메시지가 빈 문자열이 아니면 호스트 좌상단에 빨간 점 표시 + 숨김 input 의 `setCustomValidity` 로 폼 검증 연동(폼 submit 시 메시지 노출). 커스텀 컨트롤의 유효성 표시에. (sd-textfield 등 내장 컨트롤이 이미 사용)
15
+ `IntersectionObserver` 뷰포트 진입/이탈 emit.
19
16
 
20
- ## 기타 셋업 훅·유틸
17
+ - `sdIntersection: output<SdIntersectionEvent>` — 교차 변화 시 발화.
18
+ - `SdIntersectionEvent = { entry: IntersectionObserverEntry }` — `entry.isIntersecting` 으로 진입 판단. 무한 스크롤·지연 로드에 사용.
21
19
 
22
- - **setupModelHook<T>(model, canFn: Signal<(item) => boolean | Promise<boolean>>)** — model 의 set/update 를 가로채 canFn 결과가 false 면 변경 차단(Promise 면 비동기 허용). 체크박스/스위치/리스트 선택의 변경 가드(`canChangeFn`)에 사용.
23
- - **setupBgTheme(options?: { theme?; lightness? })** — body 배경색 CSS 변수를 테마색으로 설정(컴포넌트 파괴 시 복원). theme = `"primary"|...|"gray"|"blue-gray"`, lightness = `"lightest"|"lighter"`(기본 lightest). 화면 배경 톤 지정에.
24
- - **setSafeStyle(renderer: Renderer2, el, style: Partial<CSSStyleDeclaration>)** — Renderer2 로 여러 스타일 일괄 적용. 디렉티브에서 DOM 스타일 직접 조작 시.
25
- - **mark(sig: WritableSignal<any>)** — in-place 변경(배열 push 등) 후 shallow copy 새 참조로 set 하여 signal 소비자에게 변경 통지. 배열/객체를 직접 변형했을 때.
20
+ ## SdEvents (옵션부 이벤트)
26
21
 
27
- ## 타입드 템플릿 디렉티브
22
+ Angular 기본 바인딩이 못 거는 capture/passive/once 이벤트를 output 으로 노출하는 디렉티브. selector 에 든 attribute 중 쓰는 것만 바인딩하면 됨(전부 listen 하지 않음). `SdOptionEventPlugin`(provideSdAngular 가 등록) 이 실제 옵션 처리.
28
23
 
29
- - **SdTypedTemplate<T>** `<ng-template [typed]="typeToken" let-x="...">`. ng-template 컨텍스트에 타입을 부여(타입 가드). 재귀 메뉴 템플릿 등에서 컨텍스트 타입 보장에 사용.
30
- - **SdItemOfTemplate<TItem>** / **SdItemOfTemplateContext<TItem>**`<ng-template [itemOf]="items" let-item="item" let-index="index" let-depth="depth">`. 컨텍스트 `{ $implicit; item; index; depth }`. select/shared-data/calendar 등이 항목 렌더 템플릿 규약으로 사용.
24
+ - 클릭/마우스: `click.capture`, `click.once`, `click.capture.once`, `mousedown.capture`, `mouseup.capture`, `mouseover.capture`, `mouseout.capture` `output<MouseEvent>`.
25
+ - 키보드: `keydown.capture`, `keyup.capture``output<KeyboardEvent>`.
26
+ - 포커스: `focus.capture`, `blur.capture` — `output<FocusEvent>`(버블 안 되므로 capture 필수).
27
+ - 폼: `invalid.capture` — `output<Event>`.
28
+ - 스크롤/휠: `scroll.capture`, `scroll.passive`, `scroll.capture.passive`, `wheel.passive`, `wheel.capture.passive` — passive 로 스크롤 성능 확보.
29
+ - 터치: `touchstart.passive`(+capture), `touchmove.passive`(+capture), `touchend.passive` — `output<TouchEvent>`.
30
+ - 드래그: `dragover.capture`, `dragenter.capture`, `dragleave.capture`, `drop.capture` — `output<DragEvent>`.
31
+ - 애니메이션: `transitionend.once`, `animationend.once` — 1회만.
32
+ - `.capture` = 캡처 단계 수신, `.passive` = preventDefault 불가(스크롤 블로킹 방지), `.once` = 1회 후 자동 해제.
33
+ - 사용: `<div (scroll.passive)="onScroll()">`, `<div (keydown.capture)="onKeydown($event)">`.
31
34
 
32
- ## SdOptionEventPlugin
35
+ ## SdCommandDirective (`[sdRefreshCommand],[sdSaveCommand],[sdInsertCommand]`)
33
36
 
34
- `provideSdAngular` 등록하는 `EventManagerPlugin`. `.capture`/`.passive`/`.once` 접미 이벤트를 해석. 직접 사용 함.
37
+ 문서 레벨 Ctrl 단축키를 명령 output 으로. 최상위 열린 모달 안에서만 동작(다른 컨텍스트로 새지 않게 가드).
38
+
39
+ - `sdRefreshCommand: output<KeyboardEvent>` — Ctrl+Alt+L.
40
+ - `sdSaveCommand: output<KeyboardEvent>` — Ctrl+S.
41
+ - `sdInsertCommand: output<KeyboardEvent>` — Ctrl+Insert.
42
+ - 매칭 시 preventDefault + stopPropagation. `sd-crud-list`/`sd-crud-detail` 가 `sdSaveCommand` 를 hostDirective 로 받아 저장 트리거.
43
+
44
+ ## SdRipple (`[sdRipple]`) / setupRipple
45
+
46
+ 클릭 지점에서 퍼지는 물결 효과.
47
+
48
+ - `SdRipple.sdRipple: input.required(booleanAttribute)` — true 일 때만 ripple 동작(disabled 토글). `<sd-button [sdRipple]="!disabled()">`.
49
+ - `setupRipple(enableFn?: () => boolean): void` — constructor 에서 호출하는 헬퍼. `enableFn` 이 false 반환 시 해당 클릭은 ripple 생략. 커스텀 컴포넌트 내부에서 직접 ripple 부여 시.
50
+
51
+ ## SdShowEffect (`[sdShowEffect]`) / setupRevealOnShow
52
+
53
+ 뷰포트 진입 시 페이드+슬라이드로 나타나는 효과.
54
+
55
+ - `SdShowEffect.sdShowEffect: input.required(booleanAttribute)` — true 면 효과 적용, false 면 효과 없이 즉시 표시.
56
+ - `SdShowEffect.sdShowEffectType: "l2r" | "t2b"` — 등장 방향. `"t2b"`(기본) = 위에서 아래로, `"l2r"` = 왼쪽에서 오른쪽으로.
57
+ - `setupRevealOnShow(optFn?: () => { type?: "l2r"|"t2b"; enabled?: boolean }): void` — constructor 헬퍼. `enabled` false 면 트랜지션 없이 노출.
58
+
59
+ ## SdInvalid (`[sdInvalid]`) / setupInvalid
60
+
61
+ 폼 검증 실패를 좌상단 빨간 점 + 네이티브 form 검증으로 표시. 숨은 input 에 `setCustomValidity` 를 걸어 form submit 시 차단.
62
+
63
+ - `SdInvalid.sdInvalid: input.required<string>` — 빈 문자열이면 유효, 비어있지 않으면 그 메시지로 invalid 표시.
64
+ - `setupInvalid(getInvalidMessage: () => string): void` — constructor 헬퍼. 반환 문자열이 비면 valid, 아니면 invalid. 모든 입력 컨트롤(`sd-textfield`/`sd-select`/`sd-modal-select-button` 등)이 내부에서 이걸로 required/형식 검증을 구현. 커스텀 입력 컴포넌트 작성 시 동일 패턴.
65
+
66
+ ## SdTypedTemplate (`ng-template[typed]`)
67
+
68
+ `<ng-template>` 컨텍스트에 타입을 주는 디렉티브(런타임 동작 없음, 타입 가드만).
69
+
70
+ - `typed: input.required<T>` — 컨텍스트 타입 토큰. `let-x` 변수에 `T` 타입이 추론됨. 사이드바/탑바 메뉴 재귀 템플릿이 사용.
71
+
72
+ ## SdItemOfTemplate (`ng-template[itemOf]`)
73
+
74
+ 항목 반복 템플릿에 항목 타입을 주는 디렉티브.
75
+
76
+ - `itemOf: input.required<TItem[]>` — 항목 배열(타입 추론용 더미, 실제 반복은 부모가 수행).
77
+ - 컨텍스트: `SdItemOfTemplateContext<TItem> = { $implicit; item; index: number; depth: number }`. `let-item="item"` / `let-index="index"` / `let-depth="depth"`.
78
+ - 사용: `sd-shared-data-select`·`sd-calendar` 의 항목 템플릿. `<ng-template [itemOf]="items()" let-item="item">{{ item.name }}</ng-template>`.
@@ -1,40 +1,127 @@
1
- # @simplysm/angular — 기능 컴포넌트(주소검색·에디터·시각화·칸반)
2
-
3
- 특정 도메인 기능을 제공하는 독립 컴포넌트 묶음. 필요한 화면에서 개별적으로 가져다 씀.
4
-
5
- ## 주소 검색
6
-
7
- - **SdAddressSearchModal** — 다음(카카오) 우편번호 검색 모달 컴포넌트. `SdModalContentDef<Address>` 구현이라 `SdModalProvider.showAsync({ type: SdAddressSearchModal, ... })` 로 띄움. 외부 스크립트(daum postcode) 를 동적 로드. `close = output<Address>()`.
8
- - **Address** — `{ postNumber: string | undefined; address: string | undefined; buildingName: string | undefined }`. 결측은 undefined 보존.
9
-
10
- ## 에디터
11
-
12
- - **SdTiptapEditor** `<sd-tiptap-editor [(value)]="...">`tiptap 기반 리치텍스트 에디터(HTML 문자열).
13
- - value = model<string>()HTML 본문.
14
- - disabled/readonly/required: boolean 비활성/읽기전용/필수(빈 검증).
15
- - placeholder?: string.
16
- - validatorFn?: (value) => string | undefined — 커스텀 검증 메시지.
17
- - extensions?: AnyExtension[] — 추가 tiptap 확장.
18
-
19
- ## 시각화
20
-
21
- - **SdLabel** `<sd-label>` — 작은 배지/태그. `theme`(8색), `color?: string`(임의 배경색), `clickable: boolean`(호버 강조 + 커서).
22
- - **SdNote** `<sd-note>`안내 박스. `theme`(8색), `size`("sm"|"lg"), `inset: boolean`.
23
- - **SdProgress** `<sd-progress [theme]="..." [value]="...">` — 진행률 막대. `theme: input.required`(8색), `value: input.required<number>`(0~1, 백분율 표시·막대 폭은 0~100% clamp), `size`("sm"|"lg"), `inset: boolean`.
24
- - **SdCalendar<T>** `<sd-calendar [items]="..." [getItemDateFn]="...">` — 월간 달력에 항목 배치.
25
- - items: input.required<T[]>.
26
- - getItemDateFn: input.required<(item, index) => DateOnly> — 항목의 날짜.
27
- - yearMonth: input(기본 이번 1일) — 표시 월.
28
- - weekStartDay: number(기본 0=일요일) / minDaysInFirstWeek: number(기본 1) — 주 시작·첫 주 기준.
29
- - (contentChild) `itemOf` 템플릿 필수 날짜 칸 항목 렌더.
30
- - **SdBarcode** `<sd-barcode [type]="..." [value]="...">` — bwip-js 로 바코드 SVG 렌더. `type: input.required<BarcodeType>`(qrcode/code128/ean13 등 다수 `BarcodeType` 유니온 참조), `value?: string`(빈 값이면 미표시).
31
- - **SdEcharts** `<sd-echarts [option]="...">` — ECharts 차트. `option: input.required<echarts.EChartsOption>`, `notMerge: boolean`(기본 false, true 면 옵션 병합 대신 교체), `loading: boolean`(로딩 오버레이).
32
-
33
- ## 칸반
34
-
35
- - **SdKanbanBoard<L, T>** `<sd-kanban-board>` — 칸반 보드 컨테이너(드래그 앤 드롭 조율).
36
- - selectedValues = model<T[]>([]) — 선택된 카드 값(Shift+클릭 다중 선택).
37
- - (output) drop: `SdKanbanBoardDropInfo<L,T>` = `{ sourceKanbanValue?; targetLaneValue?; targetKanbanValue? }` 드롭 시 발생(소스 카드→대상 레인/카드).
38
- - **SdKanbanLane<L, T>** `<sd-kanban-lane [value]="...">` — 레인(열). `value?: L`(레인 식별), `busy: boolean`, `useCollapse: boolean`(접기 버튼) + `collapse = model(false)`, `toolTpl`/`titleTpl`(도구·제목 템플릿). 전체선택 체크박스(선택가능 카드 있을 때).
39
- - **SdKanban<L, T>** `<sd-kanban [value]="...">` — 카드. `value?: T`, `selectable: boolean`(Shift+클릭 선택 허용), `draggable: boolean`(드래그 허용), `contentClass?: string`. 드래그 다른 카드/레인 위에 드롭 위치 표시.
40
- - 타입: **SdKanbanBoardDropInfo<L,T>**(위), **SdKanbanDragRef<L,T>**(`{ value(); heightOnDrag() }`), **SdKanbanDropTarget<L,T>**(`{ targetLaneValue(); targetKanbanValue?() }`) — 보드 내부 드래그/드롭 대상 규약.
1
+ # @simplysm/angular — 기능 컴포넌트 (칸반·권한표·상태프리셋·테마선택·주소검색·에디터·시각화)
2
+
3
+ 군에 들지 않는 도메인성/표시용 컴포넌트 모음. 특정 화면 기능을 붙일 때 개별로 읽힘.
4
+
5
+ ## 칸반 (드래그 보드)
6
+
7
+ ### SdKanbanBoard<L, T> (`sd-kanban-board`)
8
+
9
+ 레인(`L`)·카드(`T`) 드래그 보드의 루트. 드래그 종료 시 drop 정보 emit.
10
+
11
+ - `selectedValues: model<T[]>` — Shift+클릭으로 선택된 카드 값들.
12
+ - `drop: output<SdKanbanBoardDropInfo<L, T>>`카드 drop 발화.
13
+ - `SdKanbanBoardDropInfo<L, T> = { sourceKanbanValue?: T; targetLaneValue?: L; targetKanbanValue?: T }` 옮긴 카드·대상 레인·대상 카드(앞에 끼움).
14
+ - `SdKanbanDragRef`/`SdKanbanDropTarget`내부 드래그/드롭 인터페이스.
15
+
16
+ ### SdKanbanLane<L, T> (`sd-kanban-lane`)
17
+
18
+ 레인(컬럼). 카드들을 담고 drop 대상이 됨.
19
+
20
+ - `value: input<L>` — 레인 값(drop 시 `targetLaneValue`).
21
+ - `busy: boolean` 레인 busy 오버레이.
22
+ - `useCollapse: boolean`접기 토글 표시. `collapse: model<boolean>` — 접힘 상태.
23
+ - 슬롯: `#titleTpl`(제목), `#toolTpl`(도구). 전체선택 체크박스는 선택 가능 카드가 있을 때.
24
+
25
+ ### SdKanban<L, T> (`sd-kanban`)
26
+
27
+ 카드. 드래그 소스 + 선택 대상.
28
+
29
+ - `value: input<T>`카드 값.
30
+ - `draggable: boolean`true 드래그 가능.
31
+ - `selectable: boolean` true 면 Shift+클릭 선택 가능.
32
+ - `contentClass: string` — 카드 본문 클래스.
33
+ - 사용: `<sd-kanban-board (drop)="onDrop($event)"><sd-kanban-lane [value]="lane"><sd-kanban [value]="card" [draggable]="true">...</sd-kanban></sd-kanban-lane></sd-kanban-board>`.
34
+
35
+ ## SdPermissionTable<TModule> (`sd-permission-table`)
36
+
37
+ 권한 트리를 표로 표시·편집(use/edit 체크박스). `SdAppStructureProvider.getPermissionsByStructure(...)` 결과를 입력.
38
+
39
+ - `value: model<Record<string, boolean>>` `<코드>.<use|edit>` 부여 여부 맵.
40
+ - `items: SdPermission<TModule>[]` 권한 트리(routing-appstructure.md `SdPermission`).
41
+ - `disabled: boolean` — 편집 비활성(조회).
42
+
43
+ ## SdStatePreset<TState> (`sd-state-preset`)
44
+
45
+ 화면 검색/필터 상태를 이름붙은 프리셋으로 저장·복원(즐겨찾기). 프리셋은 `injectSdSystemConfigResource` 로 영속.
46
+
47
+ - `key: input.required<string>` — 프리셋 저장 키.
48
+ - `state: model.required<TState>` — 현재 상태(프리셋 적용 시 이 모델에 set). 저장은 현재 state 를 스냅샷.
49
+ - `size: "sm"|"lg"` — 버튼 크기.
50
+ - `SdStatePresetDef<TState> = { name: string; state: TState }` — 저장된 프리셋 1개.
51
+ - 별(추가)·저장·삭제 동작은 내장(이름 prompt/덮어쓰기 confirm 모달 사용).
52
+
53
+ ## SdThemeProvider 관련 — SdThemeSelector (`sd-theme-selector`)
54
+
55
+ 글자 크기 증감 + 다크모드 스위치를 담은 드롭다운 UI. 내부에서 `SdThemeProvider`(infra.md)를 조작.
56
+
57
+ - (입력 없음) 탑바 등에 `<sd-theme-selector />` 로 배치. 글자 크기는 `fontSizePresets` 단계, 다크는 `dark` 토글.
58
+
59
+ ## SdAddressSearchModal (`sd-address-search-modal`)
60
+
61
+ 다음(카카오) 우편번호 검색 모달(`SdModalContentDef<Address>`). 외부 스크립트를 동적 로드해 임베드.
62
+
63
+ - `close: output<Address>` — 선택한 주소 emit.
64
+ - `initialized: Signal<boolean>` — 스크립트 로드 완료 여부.
65
+ - `Address = { postNumber?: string; address?: string; buildingName?: string }` — 결과(각 필드 결측 가능).
66
+ - 사용: `const addr = await this._sdModal.showAsync({ type: SdAddressSearchModal, title: "주소 검색", inputs: {} }); if (!addr) return;`.
67
+
68
+ ## SdTiptapEditor (`sd-tiptap-editor`)
69
+
70
+ Tiptap 기반 리치 텍스트(HTML) 에디터. 툴바 내장.
71
+
72
+ - `value: model<string>` — HTML 문자열.
73
+ - `disabled: boolean` — 비활성. `readonly: boolean` — 읽기 전용.
74
+ - `required: boolean` — 빈 값이면 invalid. `validatorFn: (value) => string | undefined` — 커스텀 검증.
75
+ - `placeholder: string` — 빈 에디터 안내.
76
+ - `extensions: AnyExtension[]` — 추가 Tiptap 확장.
77
+
78
+ ## 시각화·표시 컴포넌트 (features/visual)
79
+
80
+ ### SdLabel (`sd-label`)
81
+
82
+ 배지/태그. `<ng-content>` 본문.
83
+
84
+ - `theme: "primary"|"secondary"|"info"|"success"|"warning"|"danger"|"gray"|"blue-gray"` — 배경 색(미지정=회색 darker). 상태 표시에 의미별 색.
85
+ - `color: string` — 임의 배경색 직접 지정(theme 대신).
86
+ - `clickable: boolean` — true 면 포인터 커서 + hover 효과.
87
+
88
+ ### SdNote (`sd-note`)
89
+
90
+ 안내 박스(연한 배경). `<ng-content>` 본문.
91
+
92
+ - `theme: "primary"|...|"blue-gray"` — 박스 색(미지정=회색 lightest).
93
+ - `size: "sm"|"lg"` — 패딩.
94
+ - `inset: boolean` — 테두리 제거.
95
+
96
+ ### SdProgress (`sd-progress`)
97
+
98
+ 가로 진행 바 + 퍼센트 텍스트.
99
+
100
+ - `value: input.required<number>` — 진행값(0~1, percent 파이프로 표시).
101
+ - `theme: input.required<...>` — 바 색(필수).
102
+ - `size: "sm"|"lg"` / `inset: boolean` — 크기/테두리.
103
+
104
+ ### SdCalendar<T> (`sd-calendar`)
105
+
106
+ 월 달력 그리드에 항목을 날짜별로 배치. 항목 템플릿으로 셀 내용 렌더.
107
+
108
+ - `items: input.required<T[]>` — 표시할 항목들.
109
+ - `getItemDateFn: input.required<(item, index) => DateOnly>` — 항목의 날짜 추출.
110
+ - `yearMonth: input<DateOnly>` — 표시 연월(기본 이번 달 1일).
111
+ - `weekStartDay: number` — 주 시작 요일(0=일, 기본 0). `minDaysInFirstWeek: number` — 첫 주 최소 일수(기본 1).
112
+ - 항목 템플릿: `<ng-template [itemOf]="items()" let-item="item">`(필수).
113
+
114
+ ### SdBarcode (`sd-barcode`)
115
+
116
+ 바코드/QR 등을 SVG 로 렌더(bwip-js).
117
+
118
+ - `type: input.required<BarcodeType>` — 바코드 종류. `BarcodeType` 은 `"code128"|"qrcode"|"ean13"|"datamatrix"|...`(bwip-js 의 100+ 심볼로지 리터럴 유니온). 대표: `"code128"`(범용 1D), `"qrcode"`(QR), `"ean13"`/`"upca"`(상품), `"datamatrix"`(소형 2D).
119
+ - `value: string` — 인코딩할 데이터(빈 값이면 미렌더).
120
+
121
+ ### SdEcharts (`sd-echarts`)
122
+
123
+ ECharts 차트(SVG 렌더). 리사이즈 자동 대응.
124
+
125
+ - `option: input.required<echarts.EChartsOption>` — 차트 옵션. 변경 시 재설정.
126
+ - `notMerge: boolean` — true 면 옵션 병합 없이 교체(기본 false=병합).
127
+ - `loading: boolean` — true 면 로딩 인디케이터.
@@ -1,74 +1,91 @@
1
- # @simplysm/angular — 부트스트랩·설정·로깅·서비스 인프라
1
+ # @simplysm/angular — 부트스트랩·전역 프로바이더
2
2
 
3
- 앱 시작 시 1회 설정하는 부트스트랩 함수와 전역 프로바이더 묶음. 부팅 코드(`appConfig`/`main.ts`)·전역 에러·서버 연결·시스템 설정 저장을 다룰 때 함께 읽힘.
3
+ 앱 시작 시 1회 배선하는 `provideSdAngular` 와, `providedIn: "root"` 로 어디서든 inject 하는 전역 프로바이더(테마·로컬스토리지·시스템설정·시스템로그·서비스클라이언트·설정값)를 모은 군. 화면이 아니라 부트스트랩(`provideAppInitializer`)·앱 코드에서 같이 읽힌다.
4
4
 
5
5
  ## provideSdAngular
6
6
 
7
- `provideSdAngular(opt: { clientName: string }): EnvironmentProviders` — 앱 `providers` 에 1개 추가하면 다음을 일괄 설정. zoneless 변경감지 활성, 전역 에러 핸들러(`SdGlobalErrorHandlerPlugin`) 등록, 옵션 이벤트 플러그인(`SdOptionEventPlugin`) 등록, ng-icons 기본설정(strokeWidth 1.5, size 1.33em), `IMAGE_CONFIG` 경고 비활성, 테마 dark/fontSize 를 로컬스토리지(`sd-theme-dark`/`sd-theme-font-size`)에 자동 영속, service worker 업데이트 폴링(5분~최대1시간 지수 백오프, 갱신 감지 시 새로고침 확인), 라우터 네비게이션 동안 글로벌 busy 카운트 증감.
8
-
9
- - opt.clientName: string — 이 클라이언트 식별자. 로컬스토리지 키 prefix·service-client 연결 이름으로 사용. 앱마다 고유 문자열.
10
-
11
7
  ```ts
12
- bootstrapApplication(AppComponent, {
13
- providers: [provideRouter(routes), provideSdAngular({ clientName: "my-app" })],
14
- });
8
+ function provideSdAngular(opt: { clientName: string }): EnvironmentProviders
15
9
  ```
16
10
 
11
+ `ApplicationConfig.providers` 에 1개 넣으면 simplysm 클라이언트 동작 전체가 배선됨. 내부 처리:
12
+
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 표시.
20
+
21
+ 사용: `bootstrapApplication(AppRoot, { providers: [provideSdAngular({ clientName: CLIENT_NAME }), provideRouter(...), ...] })`.
22
+
17
23
  ## SdAngularConfigProvider
18
24
 
19
- `@Injectable({providedIn:"root"})`. `clientName: string` 필드 1개. `provideSdAngular` 가 채워줌. 다른 프로바이더가 clientName 참조할 inject.
25
+ - `clientName: string` `provideSdAngular` 가 주입하는 클라이언트 이름. 다른 provider prefix/식별자로 참조. 보통 직접 set 하지 않음.
20
26
 
21
- ## SdSystemLogProvider
27
+ ## SdThemeProvider
22
28
 
23
- 전역 로그 기록 프로바이더. 콘솔 로그 + 선택적 서버 전송.
29
+ 다크모드·기본 글자크기 전역 상태. `provideSdAngular` 로컬스토리지 동기화를 자동 배선하므로 화면에서는 토글만 호출.
24
30
 
25
- - writeFn?: (severity, ...data) => Promise<void> | void 외부(서버) 전송 훅. 지정하면 로그마다 호출. 서버 로그 적재가 필요하면 초기화 때 할당.
26
- - writeAsync(severity: "error"|"warn"|"log", ...data): Promise<void>로그 기록. 콘솔에 먼저 출력 writeFn 호출. writeFn 이 throw 해도 로깅 자체는 실패하지 않음(내부 logger.error 기록).
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)`.
27
36
 
28
37
  ## SdLocalStorageProvider<T>
29
38
 
30
- `clientName.<key>` 형태로 localStorage JSON 저장/조회. T `{ key: 값타입 }` 맵.
39
+ `localStorage` 를 `<clientName>.<key>` 네임스페이스로 JSON 직렬화해 읽고 씀. 제네릭 `T` 키→값 타입 매핑.
31
40
 
32
- - set<K>(key, value) — JSON.stringify 후 저장.
33
- - get<K>(key): T[K] | undefined — 없거나 파싱 실패 시 undefined(결측 보존).
34
- - remove(key) — 삭제.
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)`.
35
45
 
36
46
  ## SdSystemConfigProvider<T>
37
47
 
38
- 화면별 설정(시트 컬럼 상태, 모달 위치, 상태 프리셋 등) 영속 프로바이더. `fn` 미지정 로컬스토리지로 폴백.
48
+ 화면별 설정(시트 컬럼 구성, 모달 위치 등) 영속화. 외부 저장 함수(`fn`) 꽂혀 있으면 그쪽, 없으면 `SdLocalStorageProvider` 로 폴백.
39
49
 
40
- - fn?: { set(key, data): Promise|void; get(key): PromiseLike<unknown> } — 서버 영속 훅. 지정하면 서버에 저장/조회, 미지정이면 `SdLocalStorageProvider` 폴백. 서버 동기화가 필요하면 초기화 때 할당.
41
- - setAsync<K>(key, data) — data null 이면 제거(폴백 시), 아니면 저장.
42
- - getAsync(key) — 저장된 조회.
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 화해 쓰는 게 표준.
43
54
 
44
55
  ## injectSdSystemConfigResource<T>
45
56
 
46
- `injectSdSystemConfigResource<T>({ key: Signal<string|undefined> })` — 컴포넌트 내에서 호출. 호스트 엘리먼트 태그명 + key 를 합친 키로 `SdSystemConfigProvider` 에 연동되는 resource 핸들 반환. key 가 undefined 면 로드/저장 안 함.
47
-
48
- - key: Signal<string|undefined> — 설정 키 signal. 빈 값이면 비활성.
49
- - 반환: `{ value, isLoading, status, hasValue(), reload(), set(v), update(fn) }`. set/update 는 즉시 로컬 반영 후 microtask 로 비동기 영속(실패 시 errorHandler 로 전달). 시트/상태프리셋이 내부적으로 사용.
50
-
51
- ## SdServiceClientFactoryProvider
52
-
53
- `@simplysm/service-client` 연결을 key 단위로 관리하는 팩토리. 요청/응답 진행률을 토스트로 표시.
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
+ ```
54
68
 
55
- - connectAsync(key: string, options?: Partial<ServiceConnectionOptions>): Promise<void> 연결 생성. host/port/ssl 미지정 현재 location 기준 기본값. 같은 key 재연결·끊긴 key 재사용 시 throw.
56
- - closeAsync(key): Promise<void> — 연결 종료. 미연결 key 면 throw.
57
- - get(key): ServiceClient — 연결된 클라이언트 반환. 미연결/끊김이면 throw. 서비스 호출 시 이걸로 ServiceClient 획득.
69
+ `SdSystemConfigProvider` 위에 Angular `resource` 얹은 컴포넌트 스코프 헬퍼. 실제 저장 키는 `<호스트엘리먼트태그>.<key>` 자동 분리되어 같은 컴포넌트 종류끼리 설정을 공유.
58
70
 
59
- ## SdGlobalErrorHandlerPlugin
71
+ - `options.key: Signal<string | undefined>` — 설정 키 signal. `undefined` 면 로드/저장 스킵. 컴포넌트의 `key` 입력을 그대로 넘김.
72
+ - `set` — 메모리 즉시 반영 후 microtask 로 `setAsync` 영속(실패 시 ErrorHandler 로 전파, silent skip 아님).
73
+ - `sd-sheet` 가 컬럼 설정을 이걸로 보관(sheet.md 참조).
60
74
 
61
- `ErrorHandler` 구현. `provideSdAngular` 가 등록하므로 직접 쓸 일은 드묾. 처리되지 않은 에러/Promise 거부를 시스템 로그에 기록하고 전체화면 오류 오버레이를 1회 표시 후 앱을 destroy(클릭 시 새로고침). 직접 inject 하지 말고 `throw` 로 위임.
75
+ ## SdSystemLogProvider
62
76
 
63
- ## SdThemeProvider
77
+ 프레임워크가 잡은 에러/경고를 콘솔 + (배선 시) 외부 저장소로 적재. 자세한 배선·자동 적재 지점은 `client-system-log.md` 참조.
64
78
 
65
- `@Injectable({providedIn:"root"})`. 다크모드·폰트크기 전역 상태.
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
83
 
67
- - dark: WritableSignal<boolean> — 다크모드. true 면 body 에 `sd-theme-dark` 클래스 토글.
68
- - fontSize: WritableSignal<number> — 루트 폰트 크기(px). 변경 시 `documentElement.style.fontSize` 반영.
69
- - fontSizePresets: readonly number[] — `[12,14,16,20,24,28]`. 증감 단계.
70
- - increaseFontSize() / decreaseFontSize() — 프리셋 내 다음/이전 단계로 이동.
84
+ ## SdServiceClientFactoryProvider
71
85
 
72
- ## SdThemeSelector
86
+ `@simplysm/service-client` 의 `ServiceClient` 를 key 별로 생성·보관·종료. 요청/응답 진행률을 자동으로 토스트 progress 로 표시.
73
87
 
74
- `<sd-theme-selector />`폰트크기 증감·다크모드 스위치를 드롭다운으로 제공하는 컴포넌트. input 없음. `SdThemeProvider` 를 직접 조작. 탑바 등에 배치.
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 경유.
@@ -1,27 +1,63 @@
1
- # @simplysm/angular — 레이아웃(사이드바·탑바)
1
+ # @simplysm/angular — 레이아웃(사이드바·탑바)
2
2
 
3
- 화면 골격을 만드는 사이드바·탑바 컴포넌트 묶음. 메뉴 데이터는 `SdMenu`(routing-appstructure.md 참조) 또는 자체 메뉴 객체를 사용.
3
+ 셸의 좌측 사이드바·상단바와 그 안의 메뉴/사용자 메뉴 컴포넌트 군. 앱 루트 레이아웃(`app.root` 등)에서 한 번 구성. 메뉴 항목 타입(`SdMenu`)·라우터 링크는 routing-appstructure.md 것을 사용.
4
4
 
5
5
  ## 사이드바
6
6
 
7
- - **SdSidebarContainer** `<sd-sidebar-container>` — 사이드바 + 본문 레이아웃 컨테이너. input 없음. `toggle: WritableSignal<boolean>`(접힘 상태, 모바일은 backdrop 표시). 라우터 네비게이션 시작 시 자동 접힘. 자식으로 `sd-sidebar` 와 본문을 둠.
8
- - **SdSidebar** `<sd-sidebar>` — 사이드바 패널. input 없음(컨테이너의 toggle 을 따름). 좌측 고정, 모바일에서 오버레이.
9
- - **SdSidebarMenu** `<sd-sidebar-menu>` 메뉴 트리 렌더. `menus = input<SdMenu[]>([])`, `layout`("accordion"|"flat" 미지정최상위 3개 이하면 flat, 아니면 accordion), `getMenuIsSelectedFn`(선택 판정 커스텀). leaf 는 `sdRouterLink` 로 이동, `menu.url` 있으면 새 창.
10
- - **SdSidebarUser** `<sd-sidebar-user>` — 사용자 영역 + 접이식 메뉴. `userMenu = input<SdSidebarUserMenu>()`. 투영 내용(프로필) + 클릭 시 펼쳐지는 메뉴 목록. 타입 `SdSidebarUserMenu = { title: string; menus: { title; onClick }[] }`.
11
-
12
- ```html
13
- <sd-sidebar-container>
14
- <sd-sidebar>
15
- <sd-sidebar-user [userMenu]="userMenu">{{ userName }}</sd-sidebar-user>
16
- <sd-sidebar-menu [menus]="appStructure.usableMenus()" />
17
- </sd-sidebar>
18
- <router-outlet />
19
- </sd-sidebar-container>
20
- ```
7
+ ### SdSidebarContainer (`sd-sidebar-container`)
8
+
9
+ 사이드바 + 본문을 감싸는 컨테이너. 데스크톱은 사이드바 폭만큼 좌패딩, 모바일은 오버레이. 라우팅 시작자동으로 토글을 닫음(모바일 메뉴 닫힘).
10
+
11
+ - `toggle: WritableSignal<boolean>` — 사이드바 접힘(데스크톱) / 닫힘(모바일) 상태. `sd-topbar` 의 햄버거가 이걸 토글. 배경(backdrop) 클릭으로도 토글.
12
+ - 자식으로 `<sd-sidebar>` 와 본문을 둠.
13
+
14
+ ### SdSidebar (`sd-sidebar`)
15
+
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>` 로 사용자 이름/아바타 영역 배치.
21
35
 
22
36
  ## 탑바
23
37
 
24
- - **SdTopbarContainer** `<sd-topbar-container>` — 탑바 + 본문 세로 레이아웃. input 없음.
25
- - **SdTopbar** `<sd-topbar>` — 상단 바. `sidebarContainer = input<SdSidebarContainer>()`(미지정 시 주입된 컨테이너 자동 사용). 사이드바가 있으면 좌측 토글(햄버거) 버튼 표시. 제목·도구는 투영.
26
- - **SdTopbarMenu** `<sd-topbar-menu>` 드롭다운형 상단 메뉴 트리. `menus = input<SdMenu[]>([])`, `getMenuIsSelectedFn`. 최상위 메뉴별 드롭다운, leaf 클릭 시 이동·드롭다운 닫힘.
27
- - **SdTopbarUser** `<sd-topbar-user>` — 사용자 드롭다운 메뉴. `menus = input.required<SdTopbarUserMenu[]>()`. 투영 내용(이름) 클릭 시 메뉴 목록. 타입 `SdTopbarUserMenu = { title: string; onClick: () => void }`.
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
+ 상단바 가로 메뉴(드롭다운 펼침).
53
+
54
+ - `menus: SdMenu[]` — 표시할 메뉴 트리. 각 루트 메뉴가 드롭다운 버튼이 되고 children 을 팝업 리스트로.
55
+ - `getMenuIsSelectedFn: (menu: SdMenu) => boolean` — 선택 판정 커스텀.
56
+ - leaf 클릭 시 라우팅 + 드롭다운 닫힘, `url` 메뉴는 새 창.
57
+
58
+ ### SdTopbarUser (`sd-topbar-user`)
59
+
60
+ 상단바 우측 사용자 드롭다운 메뉴.
61
+
62
+ - `menus: input.required<SdTopbarUserMenu[]>` — `SdTopbarUserMenu = { title: string; onClick: () => void }`. 각 항목 클릭 시 `onClick` 실행 후 드롭다운 닫힘.
63
+ - `<ng-content>` 로 트리거 버튼 라벨(사용자 이름) 배치.