@simplysm/sd-claude 14.0.94 → 14.0.96

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 (38) hide show
  1. package/claude/references/sd-simplysm14/README.md +6 -2
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +180 -43
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +275 -125
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +54 -59
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +139 -48
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +102 -88
  7. package/claude/references/sd-simplysm14/apis/angular/kanban.md +54 -0
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +60 -36
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +127 -75
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +97 -51
  11. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +74 -58
  12. package/claude/references/sd-simplysm14/apis/angular/sheet.md +81 -60
  13. package/claude/references/sd-simplysm14/apis/excel/README.md +5 -5
  14. package/claude/references/sd-simplysm14/apis/excel/cell.md +3 -3
  15. package/claude/references/sd-simplysm14/apis/excel/style.md +2 -2
  16. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +5 -4
  17. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +2 -2
  18. package/claude/references/sd-simplysm14/manuals/client-app-structure.md +5 -3
  19. package/claude/references/sd-simplysm14/manuals/client-component.md +31 -26
  20. package/claude/references/sd-simplysm14/manuals/client-crud.md +154 -4
  21. package/claude/references/sd-simplysm14/manuals/client-demo.md +5 -18
  22. package/claude/references/sd-simplysm14/manuals/client-orm.md +3 -12
  23. package/claude/references/sd-simplysm14/manuals/client-service.md +18 -7
  24. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +24 -5
  25. package/claude/references/sd-simplysm14/manuals/data-log.md +1 -1
  26. package/claude/sd-system-prompt.md +7 -0
  27. package/claude/skills/sd-debug/SKILL.md +142 -27
  28. package/claude/skills/sd-review/SKILL.md +158 -20
  29. package/claude/skills/sd-spec/SKILL.md +53 -61
  30. package/claude/skills/sd-spec/references/format.md +476 -0
  31. package/package.json +1 -1
  32. package/claude/references/sd-simplysm14/apis/angular/infra.md +0 -82
  33. package/claude/skills/sd-debug/workflow.js +0 -390
  34. package/claude/skills/sd-review/workflow.js +0 -324
  35. package/claude/skills/sd-spec/references/format-analyze.md +0 -232
  36. package/claude/skills/sd-spec/references/format-design.md +0 -248
  37. package/claude/skills/sd-spec/workflow-analyze.js +0 -615
  38. package/claude/skills/sd-spec/workflow-design.js +0 -667
@@ -1,76 +1,167 @@
1
- # @simplysm/angular — 호스트 디렉티브·signal 헬퍼·선택 매니저
1
+ # @simplysm/angular — 호스트 디렉티브·signal 헬퍼
2
2
 
3
- DOM 관찰(리사이즈/교차)·캡처 이벤트·커맨드 단축키·ripple·노출 애니메이션·invalid 표시·타입드 템플릿을 호스트 엘리먼트에 붙이는 디렉티브와, 선택/정렬/펼침 상태를 시그널로 관리하는 매니저 함수 군. `setup*` 헬퍼는 컴포넌트 `constructor` 에서 호출(`inject(ElementRef)` 의존), `Sd*` 디렉티브는 그 헬퍼를 attribute 로 래핑.
3
+ DOM 관찰(리사이즈/교차)·캡처 이벤트·커맨드 단축키·ripple·노출 애니메이션·invalid 표시·타입드 템플릿을 호스트 엘리먼트에 붙이는 디렉티브와, signal/model 다루는 작은 헬퍼 군. `setup*` 헬퍼는 컴포넌트 `constructor`(주입 컨텍스트)에서 호출(`inject(ElementRef)` 의존), `Sd*` 디렉티브는 그 헬퍼를 attribute 로 래핑.
4
4
 
5
5
  ## DOM 관찰 디렉티브
6
6
 
7
7
  ### SdResizeDirective — `[sdResize]`
8
- ResizeObserver 로 크기 변경 감지(rAF 디바운스).
9
- - `sdResize: output<SdResizeEvent>` — `{ heightChanged: boolean; widthChanged: boolean; target: HTMLElement; contentRect: DOMRectReadOnly }`. 폭/높이 변경 여부와 새 크기.
8
+
9
+ ```ts
10
+ sdResize = output<SdResizeEvent>();
11
+ // SdResizeEvent { heightChanged: boolean; widthChanged: boolean; target: HTMLElement; contentRect: DOMRectReadOnly }
12
+ ```
13
+
14
+ - `ResizeObserver` 로 크기 변화를 rAF 디바운스해 방출. `heightChanged`/`widthChanged` 로 변경 축을 구분(불필요한 재계산 회피). 시트·collapse·echarts 가 사용.
15
+
16
+ ```html
17
+ <div (sdResize)="onResize($event)">...</div>
18
+ ```
10
19
 
11
20
  ### SdIntersectionDirective — `[sdIntersection]`
12
- IntersectionObserver 로 화면 교차 감지.
13
- - `sdIntersection: output<SdIntersectionEvent>` — `{ entry: IntersectionObserverEntry }`. 마지막 entry 전달. 무한 스크롤·등장 트리거에.
14
21
 
15
- ## 캡처 이벤트·명령 단축키
22
+ ```ts
23
+ sdIntersection = output<SdIntersectionEvent>();
24
+ // SdIntersectionEvent { entry: IntersectionObserverEntry }
25
+ ```
26
+
27
+ - `IntersectionObserver` 로 뷰포트 진입/이탈을 방출. 지연 로드·노출 트리거에 사용. `entry.isIntersecting` 으로 판정.
16
28
 
17
- ### SdEvents
18
- 표준 이벤트를 capture/passive/once 옵션으로 받는 디렉티브. 셀렉터에 등록된 속성(`(click.capture)`, `(scroll.passive)`, `(wheel.capture.passive)`, `(touchstart.passive)`, `(transitionend.once)` 등) 으로 바인딩. 각 output 은 원본 DOM 이벤트(`MouseEvent`/`KeyboardEvent`/`WheelEvent`/`TouchEvent` 등)를 emit. `.capture`=캡처 단계, `.passive`=passive 리스너, `.once`=1회.
29
+ ## 이벤트·커맨드 디렉티브
30
+
31
+ ### SdEvents — 이벤트 수식어 출력
32
+
33
+ ```ts
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
+ ```
39
+
40
+ - capture/passive/once 수식어가 붙은 DOM 이벤트를 Angular 출력으로 노출(`SdOptionEventPlugin` 과 함께 동작). 성능·캡처가 필요한 이벤트 바인딩에 사용. 호스트 디렉티브로도 쓰임(시트가 `keydown.capture` 등 사용).
41
+
42
+ ```html
43
+ <div (scroll.passive)="onScroll()" (keydown.capture)="onKeydown($event)">...</div>
44
+ ```
19
45
 
20
46
  ### SdOptionEventPlugin
21
- 위 `.capture`/`.passive`/`.once` 접미사 이벤트를 Angular 가 인식하게 하는 `EventManagerPlugin`. `provideSdAngular` 가 등록하므로 직접 쓸 일은 없음.
22
47
 
23
- ### SdCommandDirective — `[sdRefreshCommand],[sdSaveCommand],[sdInsertCommand]`
24
- 전역 키보드 단축키를 명령으로 변환(최상위 열린 모달 기준으로만 처리).
25
- - `sdRefreshCommand: output<KeyboardEvent>` — `Ctrl+Alt+L` (조회).
26
- - `sdSaveCommand: output<KeyboardEvent>` — `Ctrl+S` (저장).
27
- - `sdInsertCommand: output<KeyboardEvent>` `Ctrl+Insert` (등록).
48
+ ```ts
49
+ class SdOptionEventPlugin extends EventManagerPlugin
50
+ ```
51
+
52
+ - `.capture`/`.passive`/`.once` 수식어 이벤트를 처리하는 Angular `EVENT_MANAGER_PLUGINS`. `provideSdAngular` 가 등록(직접 사용 안 함). `SdEvents` 디렉티브의 기반.
53
+
54
+ ### SdCommandDirective — `[sdRefreshCommand]` / `[sdSaveCommand]` / `[sdInsertCommand]`
55
+
56
+ ```ts
57
+ sdRefreshCommand = output<KeyboardEvent>(); // Ctrl+Alt+L
58
+ sdSaveCommand = output<KeyboardEvent>(); // Ctrl+S
59
+ sdInsertCommand = output<KeyboardEvent>(); // Insert
60
+ ```
61
+
62
+ - 전역 키보드 단축키를 출력으로. 최상위 열린 모달 안에서만 동작(다른 화면 간섭 방지). crud 골격이 `sdSaveCommand` 로 CTRL+S 저장 연결.
63
+
64
+ ### SdGlobalErrorHandlerPlugin
65
+
66
+ ```ts
67
+ class SdGlobalErrorHandlerPlugin implements ErrorHandler
68
+ ```
69
+
70
+ - 전역 에러 핸들러. 처리되지 않은 에러/Promise 거부를 시스템 로그 적재 + 전체화면 에러 오버레이로 표시(앱 destroy 후 클릭 시 reload). `provideSdAngular` 가 `ErrorHandler` 로 등록(직접 사용 안 함).
71
+
72
+ ## 시각 효과·검증 디렉티브
73
+
74
+ ### setupRipple / SdRipple — `[sdRipple]`
75
+
76
+ ```ts
77
+ setupRipple(enableFn?: () => boolean): void;
78
+ // SdRipple: enabled = input.required({ alias: "sdRipple", transform: booleanAttribute });
79
+ ```
80
+
81
+ - 클릭 시 파동(ripple) 효과. `setupRipple` 은 constructor 에서, `[sdRipple]="true"` 디렉티브는 템플릿에서. `enableFn`/`enabled` 가 false 면 효과 비활성(disabled 컨트롤). 버튼·체크박스·리스트가 사용.
82
+
83
+ ### setupRevealOnShow / SdShowEffect — `[sdShowEffect]`
84
+
85
+ ```ts
86
+ setupRevealOnShow(optFn?: () => { type?: "l2r" | "t2b"; enabled?: boolean }): void;
87
+ // SdShowEffect: enabled = input.required({ alias: "sdShowEffect" }); sdShowEffectType = input<"l2r"|"t2b">("t2b");
88
+ ```
28
89
 
29
- ## 시각 효과·유효성 디렉티브 + setup 헬퍼
90
+ - 뷰포트 진입 페이드+슬라이드 노출 애니메이션. `type` `"t2b"`=위→아래(기본), `"l2r"`=좌→우. `enabled`=false 면 애니메이션 없이 즉시 표시.
30
91
 
31
- ### setupRipple / SdRipple
32
- 클릭 위치에서 퍼지는 ripple 효과.
33
- - `setupRipple(enableFn?: () => boolean): void` — 호스트에 ripple 부착. `enableFn` 이 false 반환 시 비활성.
34
- - `SdRipple`(`[sdRipple]`): `sdRipple: input.required<boolean>` — ripple 활성 여부.
92
+ ### setupInvalid / SdInvalid — `[sdInvalid]`
35
93
 
36
- ### setupRevealOnShow / SdShowEffect
37
- 교차 페이드+슬라이드 등장.
38
- - `setupRevealOnShow(optFn?: () => { type?: "l2r"|"t2b"; enabled?: boolean }): void` — `type` 이 등장 방향(`"t2b"` 위→아래 기본, `"l2r"` 좌→우), `enabled` false 면 애니메이션 없이 즉시 표시.
39
- - `SdShowEffect`(`[sdShowEffect]`): `sdShowEffect: input.required<boolean>`(활성), `sdShowEffectType: "l2r"|"t2b"`.
94
+ ```ts
95
+ setupInvalid(getInvalidMessage: () => string): void;
96
+ // SdInvalid: invalidMessage = input.required<string>({ alias: "sdInvalid" });
97
+ ```
40
98
 
41
- ### setupInvalid / SdInvalid
42
- 커스텀 유효성 메시지를 네이티브 폼 검증으로 표시(빨간 인디케이터 + form submit 차단).
43
- - `setupInvalid(getInvalidMessage: () => string): void` — 빈 문자열이면 유효, 아니면 그 메시지로 invalid. 숨겨진 input 의 `setCustomValidity` 로 처리.
44
- - `SdInvalid`(`[sdInvalid]`): `sdInvalid: input.required<string>` — 오류 메시지(빈 값=유효).
99
+ - 호스트에 숨김 input 을 붙여 native form 검증에 참여. `getInvalidMessage()`/`invalidMessage` 가 빈 문자열이 아니면 invalid(좌상단 빨간 인디케이터 + form 제출 차단). 폼 입력 컨트롤이 내부 사용.
45
100
 
46
101
  ## 타입드 템플릿 디렉티브
47
102
 
48
103
  ### SdTypedTemplate — `ng-template[typed]`
49
- `ng-template` 컨텍스트에 타입을 부여.
50
- - `typed: input.required<T>` — 컨텍스트 타입 토큰. `ngTemplateContextGuard` 로 `let-` 변수 타입 추론.
51
104
 
52
- ### SdItemOfTemplate<TItem> — `ng-template[itemOf]`
53
- 배열 항목 순회 템플릿에 타입 부여(셀렉트·공유데이터 선택·달력의 항목 렌더).
54
- - `itemOf: input.required<TItem[]>` — 항목 배열. 컨텍스트 `SdItemOfTemplateContext`: `$implicit`/`item: TItem`, `index: number`, `depth: number`.
105
+ ```ts
106
+ typed = input.required<T>();
107
+ ```
108
+
109
+ - `ng-template` 컨텍스트 타입을 명시(`ngTemplateContextGuard`). 재귀 메뉴/트리 템플릿에서 `let-x` 의 타입 안전성 확보. `[typed]` 에 타입 토큰을 넘김.
55
110
 
56
- ```html
57
- <ng-template [itemOf]="items()" let-item="item">{{ item.name }}</ng-template>
111
+ ### SdItemOfTemplate — `ng-template[itemOf]`
112
+
113
+ ```ts
114
+ itemOf = input.required<TItem[]>();
115
+ // SdItemOfTemplateContext<TItem> { $implicit; item; index; depth }
58
116
  ```
59
117
 
60
- ## 선택·정렬·펼침 매니저 (signal 기반)
118
+ - 반복 항목 템플릿 마커. `[itemOf]="items()"` 로 항목 타입을 추론해 `let-item`/`let-index`/`let-depth` 제공. select·shared-data·calendar 등의 항목 슬롯에 사용.
119
+
120
+ ## signal·model 헬퍼
61
121
 
62
- 목록/시트가 선택·정렬·트리펼침 상태를 시그널로 관리하도록 돕는 순수 함수. 외부 시그널을 받아 파생 시그널·조작 함수를 반환.
122
+ ### setupModelHook
123
+
124
+ ```ts
125
+ setupModelHook<T>(model: WritableSignal<T>, canFn: Signal<(item: T) => boolean | Promise<boolean>>): void;
126
+ ```
63
127
 
64
- ### useSelectionManager<TItem, TKey>
65
- - 입력: `displayItems`/`selectedKeys`(model)/`selectMode`/`getItemSelectableFn`/`trackByFn`(모두 Signal).
66
- - 반환: `hasSelectable`/`isAllSelected`(Signal), `getSelectable(item)`(true/사유문자열/undefined), `getCanChangeFn(item)`, `select`/`deselect`/`toggle`/`toggleAll`/`isSelected`. `selectMode` 가 `"single"` 이면 단일, `"multi"` 면 누적 선택. 키 비교는 `obj.equal` 으로 결측·객체 키도 안전.
128
+ - model 의 `set`/`update` 를 가로채 `canFn` 이 허용할 때만 적용. false 면 변경 거부, Promise 면 비동기 확인 후 적용(에러는 `ErrorHandler`). 체크박스·스위치·select-list 의 `canChangeFn` 이 사용.
129
+
130
+ ### mark
131
+
132
+ ```ts
133
+ mark(sig: WritableSignal<any>): void;
134
+ ```
67
135
 
68
- ### useSortingManager
69
- - 입력: `sorts: WritableSignal<SortingDef[]>`.
70
- - 반환: `defMap`(키→`{ indexText?, desc }`, 다중 정렬 시 순번 표시), `toggle(key, multiple)`(미정렬→오름차순→내림차순→해제 순환, `multiple` 이면 누적), `sort<T>(items)`(현재 정렬로 배열 정렬, null 은 앞쪽).
71
- - `SortingDef` — `{ key: string; desc: boolean }`.
136
+ - in-place mutation 한 signal 값에 shallow copy(배열/객체)로 새 참조를 만들어 변경 통지. 시트 셀에서 객체 필드를 직접 수정한 뒤 호출(`(valueChange)="mark(items)"`).
137
+
138
+ ### setSafeStyle
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 등이 사용.
153
+
154
+ ```html
155
+ {{ date | format: "yyyy-MM-dd" }}
156
+ ```
157
+
158
+ ### 타입 유틸
159
+
160
+ ```ts
161
+ DirectiveInputSignals<T> // 컴포넌트의 InputSignal 프로퍼티 → 값 타입 매핑(undefined 포함 필드는 optional)
162
+ UndefToOptional<T> // undefined 포함 프로퍼티를 optional 로 변환
163
+ WithOptional<T, K> // 특정 키 K 를 optional 로
164
+ SelectModalOutputResult<TKey> { selectedKeys: TKey[] } // 선택 모달 close 페이로드
165
+ ```
72
166
 
73
- ### useExpandingManager<T>
74
- - 입력: `items`/`expandedItems`(model)/`getChildrenFn`/`sort`.
75
- - 반환: `displayItems`(펼침 반영 평면 목록)/`hasExpandable`/`isAllExpanded`(Signal), `toggle`/`toggleAll`/`isVisible(item)`(조상이 모두 펼쳐졌는지)/`def(item)`(`ExpandItemDef`).
76
- - `ExpandItemDef<T>` — `{ item; parentDef; hasChildren; depth }`.
167
+ - `DirectiveInputSignals<T>` — 모달/토스트/인쇄의 `inputs` 타입 계산에 쓰이는 유틸(컴포넌트 input signal 을 일반 값 객체로 매핑). `SelectModalOutputResult` — 선택형 모달이 close 로 돌려주는 표준 페이로드.
@@ -1,108 +1,122 @@
1
- # @simplysm/angular — 부가 기능(칸반·권한표·상태프리셋·테마·주소·에디터·시각화)
1
+ # @simplysm/angular — 부가 기능(권한표·상태프리셋·테마·주소·에디터·시각화)
2
2
 
3
- 위 군에 들지 않는 도메인성/표시용 컴포넌트 모음. 특정 화면 기능을 붙일 때 개별로 읽힘.
3
+ 위 군에 들지 않는 도메인성/표시용 컴포넌트 모음. 특정 화면 기능을 붙일 때 개별로 읽힘. 모두 standalone `sd-*` 컴포넌트.
4
4
 
5
- ## 칸반 보드 (드래그 앤 드롭)
5
+ ## SdPermissionTable `<sd-permission-table>`
6
6
 
7
- 레인-카드 보드. `sd-kanban-board` > `sd-kanban-lane` > `sd-kanban` 중첩.
7
+ ```ts
8
+ value = model<Record<string, boolean>>({}); // "<코드>.use"/"<코드>.edit" → boolean
9
+ items = input<SdPermission<TModule>[]>([]);
10
+ disabled = input(false);
11
+ ```
12
+
13
+ - 권한 트리 편집표. `items`(`SdPermission` 트리, routing-appstructure.md)를 사용/편집 체크박스 표로 렌더. `value` 는 `<코드>.use`/`<코드>.edit` 키의 boolean 맵(양방향).
14
+ - use 미체크면 edit 불가, use 해제 시 edit 자동 해제, 부모 토글 시 하위 일괄 변경. `disabled`=전체 읽기전용. 권한 관리 화면에 사용.
8
15
 
9
- ### SdKanbanBoard<L, T> `sd-kanban-board`
10
- - `selectedValues: model<T[]>` — 선택된 카드 값(Shift+클릭 다중 선택).
11
- - `drop: output<SdKanbanBoardDropInfo<L, T>>` — 카드 드롭 시 emit. `{ sourceKanbanValue?, targetLaneValue?, targetKanbanValue? }`(이동한 카드/대상 레인/대상 카드 값).
16
+ ## SdStatePreset`<sd-state-preset>`
12
17
 
13
- ### SdKanbanLane<L, T> — `sd-kanban-lane`
14
- - `value: input<L>` 레인 식별 (드롭 대상).
15
- - `busy: boolean` 레인 busy 표시.
16
- - `useCollapse: boolean` — 접기 버튼 노출.
17
- - `collapse: model<boolean>` — 접힘 상태.
18
- - 슬롯: `#titleTpl`(레인 제목), `#toolTpl`(도구). 자식 `sd-kanban` 들 배치.
18
+ ```ts
19
+ key = input.required<string>(); state = model.required<TState>(); size = input<"sm"|"lg">();
20
+ // SdStatePresetDef<TState> { name: string; state: TState }
21
+ ```
19
22
 
20
- ### SdKanban<L, T> `sd-kanban`
21
- - `value: input<T>` 카드 값.
22
- - `selectable: boolean` — Shift+클릭 선택 가능.
23
- - `draggable: boolean` — 드래그 가능.
24
- - `contentClass: string` — 카드 클래스.
23
+ - 현재 화면 상태(`state`)를 이름붙여 저장·복원하는 프리셋 바(검색 조건 즐겨찾기 등). 별 버튼=현재 상태 저장(이름 prompt), 프리셋 클릭=상태 적용, 저장/삭제 버튼 제공.
24
+ - `key` `injectSdSystemConfigResource` 영속. `state` 는 화면이 들고 있는 상태 시그널(양방향).
25
25
 
26
- ```html
27
- <sd-kanban-board [(selectedValues)]="selected" (drop)="onDrop($event)">
28
- <sd-kanban-lane [value]="'todo'"><sd-kanban [value]="task" [draggable]="true">{{ task.title }}</sd-kanban></sd-kanban-lane>
29
- </sd-kanban-board>
26
+ ## SdThemeProvider 셀렉터
27
+
28
+ ### SdThemeSelector `<sd-theme-selector>`
29
+
30
+ ```ts
31
+ // 입력 없음. SdThemeProvider 를 inject.
30
32
  ```
31
33
 
32
- ## SdPermissionTable `sd-permission-table`
34
+ - 다크모드 토글 + 글자크기 증감 UI 드롭다운. `SdThemeProvider` 를 직접 조작(`fontSize`/`dark`). 탑바 등에 배치. provider 본체는 [README.md](./README.md) "테마·배경".
33
35
 
34
- 권한 트리(`SdPermission[]`)를 체크박스 표로 편집. routing-appstructure.md 의 `SdAppStructureProvider.getPermissionsByStructure()` 결과를 입력.
35
- - `value: model<Record<string, boolean>>` — `"코드.액션"→보유` 권한 맵(체크 상태).
36
- - `items: input<SdPermission<TModule>[]>` — 권한 트리.
37
- - `disabled: boolean` — 읽기 전용.
36
+ ## SdAddressSearchModal `<sd-address-search-modal>`
38
37
 
39
- ## SdStatePreset<TState> — `sd-state-preset`
38
+ ```ts
39
+ close = output<Address>(); // SdModalContentDef<Address>
40
+ // Address { postNumber: string | undefined; address: string | undefined; buildingName: string | undefined }
41
+ ```
40
42
 
41
- 화면 상태(필터 등) 이름 붙여 저장·복원하는 프리셋 바. 프리셋은 `injectSdSystemConfigResource(key)` 로 영속.
42
- - `key: input.required<string>` — 프리셋 저장 키(화면 식별).
43
- - `state: model.required<TState>` — 현재 화면 상태. 프리셋 클릭 시 이 모델에 복원, 저장 시 현재 값을 프리셋에 기록.
44
- - `size: "sm"|"lg"` — 크기.
45
- - `SdStatePresetDef<TState>` — `{ name: string; state: TState }`(저장 단위).
43
+ - 다음(Daum) 우편번호 검색 모달. `SdModalProvider.showAsync({ type: SdAddressSearchModal, inputs: {} })` 로 띄움. 스크립트를 동적 로드하며 실패 시 에러 메시지 표시. 선택 시 `{ postNumber, address, buildingName }` 으로 close.
46
44
 
47
- ## SdThemeSelector — `sd-theme-selector`
45
+ ```ts
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
+ ```
58
+
59
+ - 리치 텍스트(WYSIWYG) 에디터. `value` 는 HTML 문자열(빈 내용이면 undefined, 결측 보존). 내장 툴바(제목·굵게·색·정렬·목록·인용·코드블록 등) 제공.
60
+ - `extensions` 지정 시 기본 확장 대체, 미지정 시 StarterKit + 색/하이라이트/정렬/이미지/밑줄(+placeholder). `disabled`/`readonly`=편집 불가, `required`/`validatorFn`=form 검증(`setupInvalid`).
61
+
62
+ ## 시각화
63
+
64
+ ### SdLabel — `<sd-label>`
65
+
66
+ ```ts
67
+ theme = input<"primary"|"secondary"|"info"|"success"|"warning"|"danger"|"gray"|"blue-gray">();
68
+ color = input<string>(); clickable = input(false);
69
+ ```
48
70
 
49
- 글자 크기 증감 + 다크모드 토글 드롭다운. `SdThemeProvider`(infra.md) 조작. 입력 없음.
71
+ - 짧은 배지/태그. `theme` 또는 임의 `color`(배경) 지정. `clickable`=호버 강조 + 커서 포인터. 상태 표시에 사용.
72
+
73
+ ### SdNote — `<sd-note>`
74
+
75
+ ```ts
76
+ theme = input<...8색>(); size = input<"sm"|"lg">(); inset = input(false);
77
+ ```
78
+
79
+ - 안내 박스(callout). `theme` 의 옅은 배경. `inset`=라운드 제거(영역 내장). 주의/도움말 문구에 사용.
80
+
81
+ ### SdProgress — `<sd-progress>`
82
+
83
+ ```ts
84
+ theme = input.required<...8색>(); value = input.required<number>(); // 0~1
85
+ inset; size = input<"sm"|"lg">();
86
+ ```
87
+
88
+ - 진행률 막대. `value`(0~1)를 퍼센트 텍스트 + 채움 막대로 표시(0~100% clamp). `theme` 필수.
89
+
90
+ ### SdCalendar — `<sd-calendar>`
91
+
92
+ ```ts
93
+ items = input.required<T[]>(); getItemDateFn = input.required<(item: T, index: number) => DateOnly>();
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`=첫 주 판정.
100
+
101
+ ```html
102
+ <sd-calendar [items]="schedules()" [getItemDateFn]="getDate" [yearMonth]="month()">
103
+ <ng-template [itemOf]="schedules()" let-item="item">{{ item.title }}</ng-template>
104
+ </sd-calendar>
105
+ ```
106
+
107
+ ### SdBarcode — `<sd-barcode>`
108
+
109
+ ```ts
110
+ type = input.required<BarcodeType>(); value = input<string>();
111
+ // BarcodeType: "qrcode"|"code128"|"ean13"|"datamatrix"|... (bwip-js 전체 심볼 유니온)
112
+ ```
50
113
 
51
- ## SdAddressSearchModal `sd-address-search-modal`
114
+ - 바코드/QR 렌더(bwip-js SVG). `type`=심볼 종류, `value`=인코딩 문자열(빈 값이면 미표시). `BarcodeType` 는 bwip-js 가 지원하는 전체 바코드 유형 리터럴 유니온.
52
115
 
53
- 다음(Daum) 우편번호 검색 모달(`SdModalContentDef<Address>`). 스크립트를 동적 로드해 표시, 선택 시 주소 emit.
54
- - `close: output<Address>` — 선택 결과. `Address` = `{ postNumber?: string; address?: string; buildingName?: string }`(미입력 필드는 undefined 보존).
116
+ ### SdEcharts `<sd-echarts>`
55
117
 
56
118
  ```ts
57
- const addr = await sdModal.showAsync({ type: SdAddressSearchModal, title: "주소 검색", inputs: {} });
119
+ option = input.required<echarts.EChartsOption>(); notMerge = input(false); loading = input(false);
58
120
  ```
59
121
 
60
- ## SdTiptapEditor `sd-tiptap-editor`
61
-
62
- 리치텍스트(Tiptap) 에디터. 색상·정렬·목록 툴바 내장.
63
- - `value: model<string>` — HTML 값.
64
- - `disabled`/`readonly`/`required: boolean` — 상태.
65
- - `placeholder: string` — 빈 상태 안내.
66
- - `validatorFn: (value) => string | undefined` — 커스텀 검증(반환 문자열이 오류).
67
- - `extensions: AnyExtension[]` — 추가 Tiptap 확장.
68
-
69
- 보조 헬퍼 `useTiptapToolbar(opt)` — 에디터 시그널을 받아 툴바 상태/명령을 반환(`activeStates`/`activeColor`/`execCmd`/`refreshActiveStates`/`toggleColorPicker`/`applyColor` 등). `TiptapActiveStates` 는 h1/h2/bold/italic/underline/strike/bulletList/orderedList/blockquote/codeBlock/align* 의 활성 여부 맵.
70
-
71
- ## 시각화 컴포넌트
72
-
73
- ### SdLabel — `sd-label`
74
- 배지/태그.
75
- - `theme` — 테마 계열(미지정=기본 회색).
76
- - `color: string` — 직접 색상 지정.
77
- - `clickable: boolean` — 클릭 가능 스타일.
78
-
79
- ### SdNote — `sd-note`
80
- 강조 노트 블록.
81
- - `theme` — 테마 계열.
82
- - `size: "sm"|"lg"`, `inset: boolean`.
83
-
84
- ### SdProgress — `sd-progress`
85
- 진행 바.
86
- - `theme: input.required<테마 계열>` — 바 색상(필수).
87
- - `value: input.required<number>` — 진행값(0~1, 내부에서 0~100% 클램프).
88
- - `size: "sm"|"lg"`, `inset: boolean`.
89
-
90
- ### SdCalendar<T> — `sd-calendar`
91
- 월 단위 달력에 항목 배치.
92
- - `items: input.required<T[]>` — 표시 항목.
93
- - `getItemDateFn: input.required<(item, index) => DateOnly>` — 항목의 날짜.
94
- - `yearMonth: DateOnly` — 표시 연월(기본 이번 달 1일).
95
- - `weekStartDay: number` — 주 시작 요일(기본 0=일).
96
- - `minDaysInFirstWeek: number` — 첫 주 최소 일수(기본 1).
97
- - 컨텐츠: `<ng-template [itemOf]>` 로 날짜 셀 항목 렌더.
98
-
99
- ### SdBarcode — `sd-barcode`
100
- 바코드/QR SVG 렌더(bwip-js).
101
- - `type: input.required<BarcodeType>` — 심볼 종류(`qrcode`/`code128`/`ean13`/`datamatrix` 등 다수, `BarcodeType` union).
102
- - `value: string` — 인코딩할 데이터(빈 값이면 미표시).
103
-
104
- ### SdEcharts — `sd-echarts`
105
- ECharts 차트(SVG 렌더).
106
- - `option: input.required<echarts.EChartsOption>` — 차트 옵션. 변경 시 갱신.
107
- - `notMerge: boolean` — 옵션 set 시 기존과 병합하지 않고 교체.
108
- - `loading: boolean` — 로딩 오버레이.
122
+ - ECharts 차트. `option` 변경 시 `setOption` 적용(`notMerge`=true 면 기존 옵션 병합 안 함). `loading`=로딩 인디케이터. 호스트 리사이즈 시 자동 `resize`(svg 렌더).
@@ -0,0 +1,54 @@
1
+ # @simplysm/angular — 칸반(kanban)
2
+
3
+ 드래그앤드롭으로 카드를 레인 간 이동하고 카드를 다중 선택하는 칸반 보드 군. `sd-kanban-board`(보드) > `sd-kanban-lane`(레인) > `sd-kanban`(카드) 의 3계층으로 구성. `L`=레인 값 타입, `T`=카드 값 타입.
4
+
5
+ ## SdKanbanBoard — `<sd-kanban-board>`
6
+
7
+ ```ts
8
+ selectedValues = model<T[]>([]);
9
+ drop = output<SdKanbanBoardDropInfo<L, T>>();
10
+ // SdKanbanBoardDropInfo<L,T> { sourceKanbanValue?: T; targetLaneValue?: L; targetKanbanValue?: T }
11
+ ```
12
+
13
+ - 칸반 전체 보드(레인을 가로 배치). `selectedValues`=선택된 카드 값들(다중선택, model). `drop`=카드를 다른 위치에 떨군 결과(소스 카드값 + 대상 레인값 + 대상 카드값). 호스트가 `drop` 을 받아 데이터 재배치.
14
+
15
+ ```html
16
+ <sd-kanban-board [(selectedValues)]="selected" (drop)="onDrop($event)">
17
+ <sd-kanban-lane [value]="'todo'"> ... </sd-kanban-lane>
18
+ </sd-kanban-board>
19
+ ```
20
+
21
+ ## SdKanbanLane — `<sd-kanban-lane>`
22
+
23
+ ```ts
24
+ busy = input(false); useCollapse = input(false); collapse = model(false);
25
+ value = input<L>();
26
+ // 슬롯: #titleTpl(제목) #toolTpl(도구) , 콘텐츠로 <sd-kanban>
27
+ ```
28
+
29
+ - 한 레인(열). `value`=레인 식별값(drop 대상 판정·targetLaneValue). `busy`=레인 busy 오버레이, `useCollapse`=접기 토글 버튼(접으면 카드 숨김, `collapse` model).
30
+ - 선택 가능한 카드가 있으면 레인 전체선택 체크박스 자동 노출. `#titleTpl`/`#toolTpl` 로 헤더/도구 영역.
31
+
32
+ ## SdKanban — `<sd-kanban>`
33
+
34
+ ```ts
35
+ value = input<T>(); selectable = input(false); draggable = input(false);
36
+ contentClass = input<string>();
37
+ ```
38
+
39
+ - 한 카드. `value`=카드 식별값. `draggable`=드래그 이동 허용, `selectable`=Shift+클릭 다중선택 허용(`board.selectedValues` 에 토글). 콘텐츠가 카드 본문. 드래그 중 드롭 위치 표시를 내장.
40
+
41
+ ```html
42
+ <sd-kanban [value]="item" [draggable]="true" [selectable]="true">
43
+ <div>{{ item.title }}</div>
44
+ </sd-kanban>
45
+ ```
46
+
47
+ ## 드래그/드롭 타입
48
+
49
+ ```ts
50
+ SdKanbanDragRef<_L, T> { value(): T | undefined; heightOnDrag(): number }
51
+ SdKanbanDropTarget<L, T> { targetLaneValue(): L | undefined; targetKanbanValue?(): T | undefined }
52
+ ```
53
+
54
+ - `SdKanbanDragRef` — 드래그 중인 카드 참조(보드가 추적). `SdKanbanDropTarget` — 드롭 대상(레인 또는 카드가 구현). 둘 다 컴포넌트가 내부 구현하는 계약으로, 직접 다룰 일은 드묾.
@@ -1,53 +1,77 @@
1
1
  # @simplysm/angular — 레이아웃(사이드바·탑바)
2
2
 
3
- 앱 셸의 좌측 사이드바·상단바와 그 안의 메뉴/사용자 메뉴 컴포넌트 군. 앱 루트 레이아웃(`app.root` 등)에서 한 번 구성. 메뉴 항목 타입(`SdMenu`)·라우터 링크는 routing-appstructure.md 의 것을 사용.
3
+ 앱 셸의 좌측 사이드바·상단바와 그 안의 메뉴/사용자 메뉴 컴포넌트 군. 앱 루트 레이아웃(`app.root` 등)에서 한 번 구성. 메뉴 항목 타입(`SdMenu`)·라우터 링크는 [routing-appstructure.md](./routing-appstructure.md) 의 것을 사용.
4
4
 
5
5
  ## 사이드바
6
6
 
7
- ### SdSidebarContainer — `sd-sidebar-container`
8
- 사이드바 + 본문을 감싸는 컨테이너. 토글 시 본문 패딩을 조정하고 모바일에서 backdrop 표시. 라우팅 시작 시 자동 닫힘. 입력 없음(내부 `toggle` 상태 보유).
7
+ ### SdSidebarContainer — `<sd-sidebar-container>`
9
8
 
10
- ### SdSidebar — `sd-sidebar`
11
- 실제 사이드바 패널. 부모 컨테이너의 `toggle` 을 따라 슬라이드. 입력 없음. 자식으로 메뉴/유저 메뉴 배치.
9
+ ```ts
10
+ toggle: WritableSignal<boolean>;
11
+ ```
12
+
13
+ - 사이드바 + 본문을 감싸는 컨테이너. `toggle` 로 사이드바 접힘 제어(데스크탑은 본문 패딩 토글, 모바일은 backdrop). 네비게이션 시작 시 자동 닫힘. 자식 컴포넌트가 `inject` 해 접근.
14
+
15
+ ### SdSidebar — `<sd-sidebar>`
12
16
 
13
- ### SdSidebarMenu — `sd-sidebar-menu`
14
- 메뉴 트리를 리스트로 렌더.
15
- - `menus: input<SdMenu[]>` — 표시할 메뉴 트리(보통 `appStructure.usableMenus()`).
16
- - `layout: "accordion"|"flat"` — 펼침 방식. 미지정 시 루트 메뉴 3개 이하면 `"flat"`, 초과면 `"accordion"` 자동.
17
- - `getMenuIsSelectedFn: (menu) => boolean` 선택 판정 커스텀(미지정 현재 페이지 코드 일치).
17
+ ```ts
18
+ toggle = computed(...); // 부모 컨테이너의 toggle 미러
19
+ ```
20
+
21
+ - 좌측 고정 사이드바 영역. `SdSidebarContainer` 안에 두면 toggle 상태에 따라 슬라이드. 콘텐츠로 로고·메뉴·사용자를 투영.
18
22
 
19
- ### SdSidebarUser`sd-sidebar-user`
20
- 사이드바 상단 사용자 영역(이름 + 펼침 메뉴).
21
- - `userMenu: input<SdSidebarUserMenu>` — `{ icon?, title, menus: { title, onClick }[] }`. `title` 이 사용자명, `menus` 가 펼침 항목(로그아웃 등).
23
+ ### SdSidebarMenu`<sd-sidebar-menu>`
22
24
 
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>
25
+ ```ts
26
+ menus = input<SdMenu[]>([]);
27
+ layout = input<"accordion" | "accordion-expanded" | "flat">();
28
+ getMenuIsSelectedFn = input<(menu: SdMenu) => boolean>();
31
29
  ```
32
30
 
31
+ - 메뉴 트리를 사이드바 리스트로 렌더(`SdRouterLink` 연결). `layout` 미지정 시 루트 메뉴 3개 이하면 `flat`, 초과면 `accordion` 자동. `accordion-expanded`=accordion 과 동일한 클릭 토글 구조이되 모든 깊이 항목이 펼친 채로 시작(이후 클릭하면 접힘), 명시 지정 시에만 적용(자동 선택 대상 아님). `getMenuIsSelectedFn`=선택 강조 커스텀(기본은 현재 페이지 코드 매칭). `menus` 는 보통 `SdAppStructureProvider.usableMenus()`.
32
+
33
+ ### SdSidebarUser — `<sd-sidebar-user>`
34
+
35
+ ```ts
36
+ userMenu = input<SdSidebarUserMenu>();
37
+ // SdSidebarUserMenu = { icon?: string; title: string; menus: { title: string; onClick: () => Promise<void>|void }[] }
38
+ ```
39
+
40
+ - 사이드바 하단 사용자 영역. 콘텐츠로 사용자 정보를 투영하고, `userMenu` 지정 시 접이식 메뉴(로그아웃 등) 표시. 각 menu 의 `onClick` 으로 동작.
41
+
33
42
  ## 탑바
34
43
 
35
- ### SdTopbarContainer — `sd-topbar-container`
36
- 탑바 + 본문 세로 컨테이너. 입력 없음. (`sd-base-container` 가 page 모드에서 내부적으로 사용.)
44
+ ### SdTopbarContainer — `<sd-topbar-container>`
37
45
 
38
- ### SdTopbar — `sd-topbar`
39
- 상단바. 사이드바 토글 버튼 + 타이틀/명령 슬롯.
40
- - `sidebarContainer: input<SdSidebarContainer>` — 토글 대상 사이드바 컨테이너(미지정 시 inject 로 상위 컨테이너 사용). 둘 중 하나라도 있으면 토글 버튼 노출.
46
+ ```ts
47
+ // 입력 없음. flex-column 셸.
48
+ ```
41
49
 
42
- ### SdTopbarMenu `sd-topbar-menu`
43
- 상단 가로 메뉴.
44
- - `menus: input<SdMenu[]>` — 메뉴 항목.
45
- - `getMenuIsSelectedFn: (menu) => boolean` — 선택 판정 커스텀.
50
+ - 탑바 + 본문 세로 셸. 상단 `<sd-topbar>` + `flex-fill` 본문 구조로 사용(`sd-base-container` 가 page 모드에서 내부 사용).
46
51
 
47
- ### SdTopbarUser`sd-topbar-user`
48
- 상단 우측 사용자 드롭다운.
49
- - `menus: input.required<SdTopbarUserMenu[]>` — `{ title, onClick }[]`. 클릭 시 `onClick` 실행 후 드롭다운 닫힘.
52
+ ### SdTopbar`<sd-topbar>`
53
+
54
+ ```ts
55
+ sidebarContainer = input<SdSidebarContainer>();
56
+ hasSidebar = computed(...);
57
+ ```
58
+
59
+ - 상단바. 사이드바가 있으면(주입 또는 `sidebarContainer` 입력) 좌측 토글 버튼 자동 노출. 콘텐츠로 제목·액션을 투영.
60
+
61
+ ### SdTopbarMenu — `<sd-topbar-menu>`
62
+
63
+ ```ts
64
+ menus = input<SdMenu[]>([]);
65
+ getMenuIsSelectedFn = input<(menu: SdMenu) => boolean>();
66
+ ```
67
+
68
+ - 탑바에 드롭다운 형태로 메뉴 트리를 렌더. 루트 메뉴마다 드롭다운, 하위는 평면 리스트. 선택 강조는 사이드바 메뉴와 동일 규약.
69
+
70
+ ### SdTopbarUser — `<sd-topbar-user>`
71
+
72
+ ```ts
73
+ menus = input.required<SdTopbarUserMenu[]>();
74
+ // SdTopbarUserMenu = { title: string; onClick: () => void }
75
+ ```
50
76
 
51
- ### 타입
52
- - `SdSidebarUserMenu` — `{ icon?: string; title: string; menus: { title: string; onClick: () => Promise<void>|void }[] }`.
53
- - `SdTopbarUserMenu` — `{ title: string; onClick: () => void }`.
77
+ - 탑바 우측 사용자 드롭다운. 콘텐츠로 사용자 표시명을 투영, `menus` 항목 클릭 시 `onClick` 실행 후 드롭다운 닫힘.