@simplysm/sd-claude 14.0.93 → 14.0.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/references/sd-simplysm14/README.md +10 -6
- package/claude/references/sd-simplysm14/apis/angular/README.md +180 -43
- package/claude/references/sd-simplysm14/apis/angular/controls.md +275 -125
- package/claude/references/sd-simplysm14/apis/angular/crud.md +54 -59
- package/claude/references/sd-simplysm14/apis/angular/directives.md +139 -48
- package/claude/references/sd-simplysm14/apis/angular/features.md +102 -88
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +54 -0
- package/claude/references/sd-simplysm14/apis/angular/layout.md +60 -36
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +127 -75
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +97 -51
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +74 -58
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +81 -60
- package/claude/references/sd-simplysm14/apis/excel/README.md +5 -5
- package/claude/references/sd-simplysm14/apis/excel/cell.md +3 -3
- package/claude/references/sd-simplysm14/apis/excel/style.md +2 -2
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +5 -4
- package/claude/references/sd-simplysm14/apis/excel/wrapper.md +2 -2
- package/claude/references/sd-simplysm14/manuals/client-app-structure.md +4 -2
- package/claude/references/sd-simplysm14/manuals/client-component.md +24 -24
- package/claude/references/sd-simplysm14/manuals/client-crud.md +328 -0
- package/claude/references/sd-simplysm14/manuals/client-demo.md +6 -19
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +49 -0
- package/claude/references/sd-simplysm14/manuals/data-log.md +33 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +37 -0
- package/claude/sd-system-prompt.md +11 -0
- package/claude/skills/sd-debug/SKILL.md +142 -27
- package/claude/skills/sd-review/SKILL.md +158 -20
- package/claude/skills/sd-spec/SKILL.md +1 -0
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/apis/angular/infra.md +0 -82
- package/claude/skills/sd-debug/workflow.js +0 -390
- package/claude/skills/sd-review/workflow.js +0 -324
|
@@ -1,79 +1,100 @@
|
|
|
1
1
|
# @simplysm/angular — 시트(sd-sheet)
|
|
2
2
|
|
|
3
|
-
다건 목록·편집 표(그리드). 컬럼 디렉티브 + 셀 템플릿으로 구성하며, 선택·정렬·페이지·트리펼침·셀 편집·컬럼 고정/리사이즈/설정저장을 내장. `sd-crud-list` 는 이 시트를 감싼 표준 골격(crud.md).
|
|
4
|
-
|
|
5
|
-
## SdSheet
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- `
|
|
31
|
-
- `
|
|
32
|
-
- `
|
|
33
|
-
- `
|
|
3
|
+
다건 목록·편집 표(그리드). 컬럼 디렉티브 + 셀 템플릿으로 구성하며, 선택·정렬·페이지·트리펼침·셀 편집·컬럼 고정/리사이즈/설정저장을 내장. `sd-crud-list` 는 이 시트를 감싼 표준 골격([crud.md](./crud.md)). 셀은 항상 `<ng-template [cell]="items()" let-item="item">` 안에 렌더.
|
|
4
|
+
|
|
5
|
+
## SdSheet — `<sd-sheet>`
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
key = input<string>(); items = input<TItem[]>([]);
|
|
9
|
+
trackByFn = input<(item: TItem, index: number) => unknown>((item) => item);
|
|
10
|
+
selectMode = input<"single" | "multi">();
|
|
11
|
+
autoSelect = input<"click" | "focus">();
|
|
12
|
+
getItemSelectableFn = input<(item: TItem) => boolean | string>();
|
|
13
|
+
getChildrenFn = input<(item: TItem, index: number) => TItem[] | undefined>();
|
|
14
|
+
useAutoSort = input(false);
|
|
15
|
+
visiblePageCount = input(10); totalPageCount = input(0); itemsPerPage = input(0);
|
|
16
|
+
focusMode = input<"row" | "cell">("cell");
|
|
17
|
+
inset = input(false); contentStyle = input<string>(); hideConfigBar = input(false);
|
|
18
|
+
getItemCellClassFn = input<(item, colKey) => string>();
|
|
19
|
+
getItemCellStyleFn = input<(item, colKey) => string | undefined>();
|
|
20
|
+
|
|
21
|
+
// outputs
|
|
22
|
+
itemKeydown = output<SdSheetItemKeydownEventParam<TItem>>(); // { item, event }
|
|
23
|
+
cellKeydown = output<SdSheetCellKeydownEventParam<TItem>>(); // { item, key, event }
|
|
24
|
+
// models
|
|
25
|
+
selectedKeys = model<unknown[]>([]); expandedItems = model<TItem[]>([]);
|
|
26
|
+
sorts = model<SortingDef[]>([]); currentPage = model(0);
|
|
27
|
+
columnControlsInput = input<readonly SdSheetColumn[]>([]); // 외부에서 컬럼 주입(crud 가 사용)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `key` — 지정 시 사용자 컬럼 설정(폭/고정/숨김/순서)을 `injectSdSystemConfigResource` 로 영속(설정 버튼·설정 모달 노출). 미지정이면 설정 저장 없음.
|
|
31
|
+
- `trackByFn` — 행 키 함수. `selectedKeys` 가 이 키 기준으로 동작. 서버 키가 있으면 그 키 반환.
|
|
32
|
+
- `selectMode` — `"single"`=단일(좌측 화살표), `"multi"`=다중(좌측 체크박스+전체선택). undefined=선택 비활성. `autoSelect` `"click"`=행/셀 클릭 시 선택, `"focus"`=셀 포커스만으로 선택(키보드 위주).
|
|
33
|
+
- `getItemSelectableFn` — 행별 선택 가능. `true`=가능, `false`=불가, `string`=불가+사유(툴팁). 본인 계정 삭제 차단 등.
|
|
34
|
+
- `getChildrenFn` — 자식 반환(트리). 지정 시 펼침 컬럼·들여쓰기 표시, `expandedItems` 로 펼친 항목 관리.
|
|
35
|
+
- `useAutoSort` — true 면 `sorts` 변경 시 시트가 직접 `items` 클라이언트 정렬. 서버측 정렬/페이징이면 false 로 두고 외부에서 재조회. `itemsPerPage>0`+`useAutoSort` 면 클라이언트 페이징, `totalPageCount>0` 이면 서버 페이징.
|
|
36
|
+
- `focusMode` — `"cell"`=셀 단위 포커스 이동(편집·복사), `"row"`=행 단위(셀 인디케이터 숨김). `hideConfigBar`=상단 설정/페이징 바 숨김, `inset`=테두리 제거.
|
|
37
|
+
- `getItemCellClassFn`/`getItemCellStyleFn` — 행+컬럼키별 클래스/스타일(예: 삭제행 취소선). `columnControlsInput` 은 래퍼(crud)가 자식 컬럼을 시트로 위임 투영할 때 사용.
|
|
34
38
|
|
|
35
39
|
```html
|
|
36
|
-
<sd-sheet [items]="items()" [(selectedKeys)]="selectedKeys"
|
|
37
|
-
|
|
40
|
+
<sd-sheet [items]="items()" [trackByFn]="trackByFn" [(selectedKeys)]="selectedKeys"
|
|
41
|
+
[selectMode]="'multi'" [(sorts)]="sorts" [key]="'order-list'">
|
|
38
42
|
<sd-sheet-column [key]="'name'" [header]="'이름'">
|
|
39
|
-
<ng-template [cell]="items()" let-item="item"
|
|
43
|
+
<ng-template [cell]="items()" let-item="item">{{ item.name }}</ng-template>
|
|
40
44
|
</sd-sheet-column>
|
|
41
45
|
</sd-sheet>
|
|
42
46
|
```
|
|
43
47
|
|
|
44
|
-
## SdSheetColumn
|
|
48
|
+
## SdSheetColumn — `<sd-sheet-column>`
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
key = input.required<string>();
|
|
52
|
+
header = input<string | string[]>(""); // string[] = 다단 헤더(병합)
|
|
53
|
+
headerStyle; tooltip; width = input<string>();
|
|
54
|
+
fixed = input(false); hidden = input(false); collapse = input(false);
|
|
55
|
+
disableSorting = input(false); disableResizing = input(false); ordering = input(0);
|
|
56
|
+
cellTplRef = contentChild.required(SdSheetColumnCellTemplate); // [cell] 템플릿(필수)
|
|
57
|
+
headerTplRef = contentChild<TemplateRef<void>>("headerTpl");
|
|
58
|
+
summaryTplRef = contentChild<TemplateRef<void>>("summaryTpl");
|
|
59
|
+
```
|
|
45
60
|
|
|
46
|
-
|
|
61
|
+
- `key` — 컬럼 식별자(정렬/설정/cellKeydown 키). `header` 배열이면 다단 헤더로 병합 표시.
|
|
62
|
+
- `width` — CSS 폭(예: `"120px"`). `fixed`=좌측 고정, `hidden`=숨김, `collapse`=설정상 접힘 후보. `disableSorting`/`disableResizing`=정렬/폭조정 비활성, `ordering`=기본 정렬 순서.
|
|
63
|
+
- `#headerTpl`/`#summaryTpl` 로 헤더/요약행 커스터마이즈. 셀 본문은 `<ng-template [cell]="items()">`(필수).
|
|
47
64
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- `tooltip: string` — 헤더 툴팁.
|
|
52
|
-
- `width: string` — 컬럼 폭(미지정이 기본=자동). px 지정은 명시 지시 시에만.
|
|
53
|
-
- `fixed: boolean` — 좌측 고정 컬럼.
|
|
54
|
-
- `hidden: boolean` — 숨김.
|
|
55
|
-
- `collapse: boolean` — 접힘(헤더만, 폭 최소).
|
|
56
|
-
- `disableSorting: boolean` — 정렬 비활성.
|
|
57
|
-
- `disableResizing: boolean` — 폭 리사이즈 비활성.
|
|
58
|
-
- `ordering: number` — 컬럼 표시 순서.
|
|
59
|
-
- 컨텐츠: `<ng-template [cell]="items()" let-item="item">`(셀 본문), `#headerTpl`(커스텀 헤더), `#summaryTpl`(요약 행).
|
|
65
|
+
```ts
|
|
66
|
+
// SdSheetCellContext<T> = { $implicit: T; item: T; index: number; depth: number; edit: boolean }
|
|
67
|
+
```
|
|
60
68
|
|
|
61
|
-
셀
|
|
69
|
+
- 셀 템플릿 컨텍스트: `item`/`index`/`depth`(트리 깊이)/`edit`(현재 셀 편집모드 여부).
|
|
62
70
|
|
|
63
|
-
## SdSheetColumnCellTemplate
|
|
71
|
+
## SdSheetColumnCellTemplate — `ng-template[cell]`
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
```ts
|
|
74
|
+
cell = input.required<T[]>(); // 타입 추론용 — items() 를 그대로 전달
|
|
75
|
+
```
|
|
66
76
|
|
|
67
|
-
-
|
|
77
|
+
- 셀 본문 템플릿 마커. `[cell]="items()"` 로 항목 배열을 넘겨 `let-item` 타입을 추론. 값 자체는 추론에만 쓰임.
|
|
68
78
|
|
|
69
|
-
## SdSheetConfigModal
|
|
79
|
+
## SdSheetConfigModal — `<sd-sheet-config-modal>`
|
|
70
80
|
|
|
71
|
-
|
|
81
|
+
```ts
|
|
82
|
+
sheetKey = input.required<string>();
|
|
83
|
+
controls = input.required<readonly SdSheetColumn[]>();
|
|
84
|
+
config = input.required<SdSheetConfig | undefined>();
|
|
85
|
+
close = output<SdSheetConfig | undefined>(); // SdModalContentDef
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- 컬럼 고정/순서/폭/숨김을 편집하는 설정 모달. `sd-sheet` 가 설정 버튼 클릭 시 자동으로 띄우며 결과를 `key` 설정으로 저장. 직접 호출할 일은 거의 없음.
|
|
72
89
|
|
|
73
|
-
## 타입
|
|
90
|
+
## 관련 타입
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
SdSheetColumnDef { key; header: string|string[]; headerStyle?; tooltip?; width?; fixed; hidden; collapse; disableSorting; disableResizing; ordering }
|
|
94
|
+
SdSheetHeaderDef { text; colspan; rowspan; isLastRow; fixed; colDef?; colIndex }
|
|
95
|
+
SdSheetConfig { columnRecord: Record<string, { width?; hidden?; fixed?; ordering? }> }
|
|
96
|
+
SdSheetItemKeydownEventParam<T> { item: T; event: KeyboardEvent }
|
|
97
|
+
SdSheetCellKeydownEventParam<T> { item: T; key: string; event: KeyboardEvent }
|
|
98
|
+
```
|
|
74
99
|
|
|
75
|
-
- `SdSheetColumnDef` —
|
|
76
|
-
- `SdSheetHeaderDef` — 다단 헤더 셀 정의(`text`/`colspan`/`rowspan`/`isLastRow`/`fixed`/`colDef`/`colIndex`).
|
|
77
|
-
- `SdSheetConfig` — 영속화되는 컬럼별 사용자 설정(`columnRecord[key] = { width?, hidden?, fixed?, ordering? }`).
|
|
78
|
-
- `SdSheetItemKeydownEventParam<T>` — `{ item, event }`(행 키다운 페이로드).
|
|
79
|
-
- `SdSheetCellKeydownEventParam<T>` — `{ item, key, event }`(셀 키다운 페이로드).
|
|
100
|
+
- `SdSheetColumnDef`/`SdSheetHeaderDef` — 레이아웃 엔진이 산출하는 컬럼/헤더셀 메타(내부 타입). `SdSheetConfig` — 영속 컬럼 설정. `SdSheet*KeydownEventParam` — `itemKeydown`/`cellKeydown` 출력 페이로드(행 단축키·셀 단축키 처리용).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @simplysm/excel
|
|
2
2
|
|
|
3
|
-
OOXML(.xlsx) 워크북을 ZIP 단위 lazy-load 로 읽고 쓰는 라이브러리. 접근한 셀에 필요한 XML 파트(SharedStrings/Styles 등)만 그때그때 로드하므로 모든 셀/시트 I/O 메서드가 `async` 다. `ExcelWorkbook` 진입점에서 시트 추가·셀 값/수식·스타일·조건부 서식·이미지·행 복사·뷰를, `ExcelWrapper` 로 Zod 스키마 기반 레코드 배열 ↔ 엑셀 변환을, `ExcelUtils` 로 주소·날짜 시리얼·숫자형식 변환을 다룬다. 외부 의존은 `@simplysm/core-common`(DateOnly/DateTime/Time/Bytes), `zod`, `mime`.
|
|
3
|
+
OOXML(.xlsx) 워크북을 ZIP 단위 lazy-load 로 읽고 쓰는 라이브러리. 접근한 셀에 필요한 XML 파트(SharedStrings/Styles 등)만 그때그때 로드하므로 거의 모든 셀/시트 I/O 메서드가 `async` 다. `ExcelWorkbook` 진입점에서 시트 추가·셀 값/수식·스타일·조건부 서식·이미지·행 복사·뷰를, `ExcelWrapper` 로 Zod 스키마 기반 레코드 배열 ↔ 엑셀 변환을, `ExcelUtils` 로 주소·날짜 시리얼·숫자형식 변환을 다룬다. 외부 의존은 `@simplysm/core-common`(DateOnly/DateTime/Time/Bytes), `zod`, `mime`.
|
|
4
4
|
|
|
5
5
|
## 사용 트리거 인덱스
|
|
6
6
|
|
|
7
|
-
- **ExcelWorkbook / ExcelWorksheet** — .xlsx 를 열거나 새로 만들고, 시트 추가/조회/이름, 데이터 테이블·매트릭스·레코드 읽기·쓰기, 행 복사/삽입, 뷰(zoom/freeze/탭색), 이미지 삽입, 바이트/Blob 내보내기를 할 때. 자세히: [workbook-worksheet.md](./workbook-worksheet.md)
|
|
7
|
+
- **ExcelWorkbook / ExcelWorksheet** — .xlsx 를 열거나 새로 만들고, 시트 추가/조회/이름, 데이터 테이블·매트릭스·레코드 읽기·쓰기, 행 복사/삽입, 뷰(zoom/freeze/autoFilter/탭색), 이미지 삽입, 바이트/Blob 내보내기를 할 때. 자세히: [workbook-worksheet.md](./workbook-worksheet.md)
|
|
8
8
|
- **ExcelCell / ExcelRow / ExcelCol** — 개별 셀의 값·수식·병합·스타일을 읽고 쓰거나, 행/열 단위로 셀을 순회하고 열 너비를 줄 때. 자세히: [cell.md](./cell.md)
|
|
9
9
|
- **셀 스타일 (ExcelStyleOptions / ExcelFont)** — 셀(`cell.setStyle`)이나 워크북 default(`wb.setDefaultStyle`)의 배경·테두리·정렬·숫자형식·폰트를 지정할 때. 자세히: [style.md](./style.md)
|
|
10
10
|
- **조건부 서식 (ExcelConditionalRule / ExcelConditionalRuleStyle)** — 셀/범위에 값 비교·텍스트 매칭·수식 기반 native CF 규칙을 추가할 때. 자세히: [conditional-format.md](./conditional-format.md)
|
|
@@ -18,7 +18,7 @@ OOXML(.xlsx) 워크북을 ZIP 단위 lazy-load 로 읽고 쓰는 라이브러리
|
|
|
18
18
|
`./types` 가 노출하는 사용자 대면 값/형식 타입. 셀 값을 다루거나 메서드 시그니처를 해석할 때 참조.
|
|
19
19
|
|
|
20
20
|
- `ExcelValueType` = `number | string | DateOnly | DateTime | Time | boolean | undefined` — 셀이 가질 수 있는 값 유니온. `getValue()` 반환·`setValue()` 인자 타입. `undefined` = "값 없음"(읽기 시 빈 셀, 쓰기 시 셀 삭제)이므로 결측을 끝까지 보존한다. `DateOnly`/`DateTime`/`Time` 은 `@simplysm/core-common` 타입이며 셀에 시리얼 숫자 + 날짜 numFmt 로 저장된다.
|
|
21
|
-
- `ExcelNumberFormat` = `"number" | "string" | "DateOnly" | "DateTime" | "Time"` — 숫자형식 프리셋 이름. `"number"` = 일반
|
|
21
|
+
- `ExcelNumberFormat` = `"number" | "string" | "DateOnly" | "DateTime" | "Time"` — 숫자형식 프리셋 이름. `"number"` = 일반 수치(numFmtId 0), `"string"` = 텍스트 형식(numFmtId 49), `"DateOnly"`(14)/`"DateTime"`(22)/`"Time"`(18) = 날짜/시간 시리얼 해석·표시. `ExcelStyleOptions.numberFormat` 와 `ExcelUtils` 변환의 공용 단위. 날짜 셀은 값으로 직접 `DateOnly`/`Time` 을 넣으면 numFmt 가 자동 부여되므로 따로 지정할 필요가 적다.
|
|
22
22
|
- `ExcelCellType` = `"s" | "b" | "str" | "n" | "inlineStr" | "e"` — OOXML 셀 `t` 속성. `"s"` = SharedString 인덱스 참조, `"b"` = boolean(`"1"`/`"0"`), `"str"` = 수식 결과 문자열, `"n"` = 숫자, `"inlineStr"` = 인라인 서식 텍스트, `"e"` = 에러(읽기 시 throw). 보통 `getValue`/`setValue` 가 자동 매핑하므로, 외부 생성 파일의 셀 타입을 직접 분기 검사할 때만 참조. 숫자/날짜 셀은 타입 코드가 `null` 이고 스타일 numFmt 로 구분된다.
|
|
23
23
|
- `ExcelAddressPoint` = `{ r: number; c: number }` — 0 기반 행(`r`)·열(`c`) 좌표. 셀 단일 위치 단위. `cell(r, c)` 인덱스와 동일 0 기반.
|
|
24
24
|
- `ExcelAddressRangePoint` = `{ s: ExcelAddressPoint; e: ExcelAddressPoint }` — 범위 좌표. `s` = 시작(좌상단), `e` = 끝(우하단, inclusive). `getRange()` 반환 타입이며 시트 순회 루프 경계로 쓴다.
|
|
@@ -29,12 +29,12 @@ OOXML(.xlsx) 워크북을 ZIP 단위 lazy-load 로 읽고 쓰는 라이브러리
|
|
|
29
29
|
|
|
30
30
|
## OOXML XML-shape 타입
|
|
31
31
|
|
|
32
|
-
`./types` 가 함께 export 하는 다음 인터페이스·타입은 라이브러리 내부 XML 파서/직렬화기가 OOXML 파트의 파싱 결과(
|
|
32
|
+
`./types` 가 함께 export 하는 다음 인터페이스·타입은 라이브러리 내부 XML 파서/직렬화기가 OOXML 파트의 파싱 결과(`$`=속성, 자식은 단일 원소 배열로 래핑되는 xml2js 스타일)를 표현하는 데이터 모델이다. 일반 사용 흐름(값/스타일/시트 API)에서는 직접 다루지 않으며, OOXML 노드를 직접 조작·검증할 때만 참조한다. 풀이는 각 타입이 표현하는 파트 1줄로 한정.
|
|
33
33
|
|
|
34
34
|
- `ExcelXmlContentTypeData` — `[Content_Types].xml` 의 `Types`(Default 확장자 매핑·Override 파트 등록) 구조.
|
|
35
35
|
- `ExcelXmlRelationshipData` / `ExcelRelationshipData` — `*.rels` 의 `Relationships` 컨테이너 및 개별 `Relationship`(Id/Target/Type) 구조.
|
|
36
36
|
- `ExcelXmlWorkbookData` — `xl/workbook.xml` 의 `workbook`(bookViews/sheets 등) 구조.
|
|
37
|
-
- `ExcelXmlWorksheetData` — `xl/worksheets/sheetN.xml` 의 `worksheet`(sheetPr 탭색/dimension/sheetViews 뷰·틀고정/cols 열너비/sheetData 행·셀/mergeCells/conditionalFormatting/drawing) 구조.
|
|
37
|
+
- `ExcelXmlWorksheetData` — `xl/worksheets/sheetN.xml` 의 `worksheet`(sheetPr 탭색/dimension/sheetViews 뷰·틀고정/cols 열너비/sheetData 행·셀/autoFilter 헤더 필터/mergeCells/conditionalFormatting/drawing) 구조.
|
|
38
38
|
- `ExcelXmlConditionalFormattingData` / `ExcelXmlCfRuleData` — `<conditionalFormatting sqref="...">` 블록과 `<cfRule>`(type/operator/priority/dxfId/text/formula) 구조. `ExcelXmlCfRuleData["$"]["type"|"operator"]` 인덱스 타입은 규칙 spec 빌드 시 내부에서 참조된다.
|
|
39
39
|
- `ExcelRowData` / `ExcelCellData` — `<row r="..">` 과 `<c r=".." s="스타일ID" t="타입">`(v=값, f=수식, is=인라인 문자열) 구조.
|
|
40
40
|
- `ExcelXmlDrawingData` — `xl/drawings/drawingN.xml` 의 `wsDr`(twoCellAnchor from/to 앵커, pic/blipFill/spPr 이미지 노드) 구조.
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
값/수식:
|
|
12
12
|
|
|
13
|
-
- `getValue(): Promise<ExcelValueType>` — 셀 값을 타입 추론해 반환. SharedString→string, `b`→boolean,
|
|
14
|
-
- `setValue(val: ExcelValueType): Promise<void>` — 값 쓰기. `string`→SharedString 등록 후 `s` 타입, `boolean`→`b` 타입(`"1"`/`"0"`), `number
|
|
13
|
+
- `getValue(): Promise<ExcelValueType>` — 셀 값을 타입 추론해 반환. SharedString(`s`)→string, `str`/`inlineStr`→string, `b`→boolean, 빈 셀→`undefined`. 타입 코드가 없는 셀은 스타일 numFmt 로 분기: 숫자형→number, 텍스트형(`string`)→string, 날짜/시간형→`DateOnly`/`DateTime`/`Time`. 셀 타입이 `e`(에러)이거나 시리얼/ID 파싱 실패면 throw.
|
|
14
|
+
- `setValue(val: ExcelValueType): Promise<void>` — 값 쓰기. `string`→SharedString 등록 후 `s` 타입, `boolean`→`b` 타입(`"1"`/`"0"`), `number`→숫자(타입 코드 없음), `DateOnly`/`DateTime`/`Time`→시리얼 숫자 + 해당 날짜 numFmt 자동 부여, `undefined`/`null`→셀 삭제. 그 외 타입은 throw. 날짜형이면 문자열 변환 없이 날짜 객체를 그대로 넘겨 자동 서식을 받는 게 단순.
|
|
15
15
|
- `getFormula(): Promise<string | undefined>` — 셀 수식 문자열 반환(없으면 `undefined`).
|
|
16
16
|
- `setFormula(val: string | undefined): Promise<void>` — 수식 설정. 셀 타입을 `str` 로 두고 캐시 값(v)은 비운다. `undefined` 면 셀 삭제. 수식 문자열은 `=` 없이 본문만(예: `"SUM(A1:A3)"`).
|
|
17
17
|
|
|
@@ -39,7 +39,7 @@ const v = await ws.cell(1, 0).getValue(); // DateOnly 로 복원
|
|
|
39
39
|
`ws.row(r)` 로 얻는다.
|
|
40
40
|
|
|
41
41
|
- `cell(c: number): ExcelCell` — 이 행의 0 기반 열 `c` 셀 반환.
|
|
42
|
-
- `getCells(): Promise<ExcelCell[]>` — 이 행에서 시트 range 의 열 범위에 해당하는 셀들을 배열로 반환(인덱스 = 열 번호, 앞쪽
|
|
42
|
+
- `getCells(): Promise<ExcelCell[]>` — 이 행에서 시트 range 의 열 범위에 해당하는 셀들을 배열로 반환(인덱스 = 열 번호, range 시작 전 앞쪽 인덱스는 비어 있음).
|
|
43
43
|
|
|
44
44
|
## ExcelCol
|
|
45
45
|
|
|
@@ -22,7 +22,7 @@ interface ExcelStyleOptions {
|
|
|
22
22
|
- `verticalAlign?: "center" | "top" | "bottom"` — 세로 정렬. `"center"` = 가운데, `"top"`/`"bottom"` = 위/아래. 행 높이가 큰 셀에서 의미.
|
|
23
23
|
- `numberFormat?: "number" | "string" | "DateOnly" | "DateTime" | "Time"` — 숫자형식 프리셋. `"number"` = 일반 수치(numFmtId 0), `"string"` = 텍스트(49), `"DateOnly"`(14)/`"DateTime"`(22)/`"Time"`(18) = 날짜/시간 표시. 표준 형식이면 이걸로 충분.
|
|
24
24
|
- `numberFormatCode?: string` — 커스텀 엑셀 formatCode(예 `"0.000000"`, `"#,##0.00"`, `"0.00%"`). `numberFormat` 과 동시 지정 시 이 필드가 우선. 천단위·소수 자릿수·퍼센트 등 세밀한 표시가 필요할 때.
|
|
25
|
-
- `font?: ExcelFont` — 폰트 묶음(아래). 일부 속성만 줘도 되며, 미지정 속성은
|
|
25
|
+
- `font?: ExcelFont` — 폰트 묶음(아래). 일부 속성만 줘도 되며, 미지정 속성은 엑셀 기본/워크북 default 폰트로 표시.
|
|
26
26
|
|
|
27
27
|
## ExcelFont
|
|
28
28
|
|
|
@@ -67,7 +67,7 @@ await wb.setDefaultStyle({ font: { family: "맑은 고딕", size: 10 } });
|
|
|
67
67
|
|
|
68
68
|
## 주의사항
|
|
69
69
|
|
|
70
|
-
- `setDefaultStyle` 은 styles.xml 의 0번 자원 슬롯(font/fill/border)을 덮어쓴다 — fontId/fillId/borderId 를 명시하지 않은 모든 셀이 영향을 받는다. 옵션에 없는 자원은 0번 슬롯이 빈 슬롯으로 reset 되므로, default 로 줄 항목은 한 번에 모아 호출.
|
|
70
|
+
- `setDefaultStyle` 은 styles.xml 의 0번 자원 슬롯(font/fill/border)을 덮어쓴다 — fontId/fillId/borderId 를 명시하지 않은 모든 셀이 영향을 받는다. 옵션에 없는 자원은 0번 슬롯이 빈 슬롯으로 reset 되므로, default 로 줄 항목은 한 번에 모아 호출. horizontalAlign/verticalAlign/numberFormat/numberFormatCode 는 `cellXfs[0].xf[0]` 에 직접 박힌다.
|
|
71
71
|
- `numberFormat` 과 `numberFormatCode` 동시 지정 시 `numberFormatCode` 우선.
|
|
72
72
|
- 색상은 모두 ARGB 8자리(알파 포함). RGB 6자리만 주면 의도와 다르게 해석될 수 있다.
|
|
73
73
|
- 날짜/시간 셀은 값으로 `DateOnly`/`DateTime`/`Time` 을 넣으면 numFmt 가 자동 부여되므로 보통 `numberFormat` 을 따로 줄 필요가 없다.
|
|
@@ -80,7 +80,8 @@ try {
|
|
|
80
80
|
|
|
81
81
|
- `setTabColor(color: string): Promise<void>` — 시트 탭 색(ARGB 8자리, 예 `"00FF0000"`). 시트 구분 강조용.
|
|
82
82
|
- `setZoom(percent: number): Promise<void>` — 확대/축소 비율(퍼센트). 워크북 뷰를 함께 초기화한다.
|
|
83
|
-
- `freezeAt(point: { r?: number; c?: number }): Promise<void>` — 틀 고정. `r` = 위쪽 고정할 행 분할 지점, `c` = 왼쪽 고정할 열 분할 지점(0 기반). 헤더 한 줄 고정이면 `{ r: 0 }`(0행까지 위가 고정되고 1행부터 스크롤).
|
|
83
|
+
- `freezeAt(point: { r?: number; c?: number }): Promise<void>` — 틀 고정. `r` = 위쪽 고정할 행 분할 지점, `c` = 왼쪽 고정할 열 분할 지점(0 기반). 헤더 한 줄 고정이면 `{ r: 0 }`(0행까지 위가 고정되고 1행부터 스크롤). 워크북 뷰를 함께 초기화한다.
|
|
84
|
+
- `setAutoFilter(range: ExcelAddressRangePoint): Promise<void>` — 헤더 자동 필터(드롭다운) 설정. `range`(`{s,e}`, 0 기반, 양끝 inclusive) = 필터를 거는 범위로 보통 헤더행~데이터 끝 전체를 덮는다. `getRange()` 반환값을 그대로 넘겨 표 전체에 적용할 수 있다.
|
|
84
85
|
|
|
85
86
|
조건부 서식:
|
|
86
87
|
|
|
@@ -98,7 +99,7 @@ try {
|
|
|
98
99
|
|
|
99
100
|
- `addImage(opts): Promise<void>` — 시트에 이미지 삽입. 같은 시트에 여러 번 호출하면 기존 drawing 파트에 이어 붙인다.
|
|
100
101
|
- `opts.bytes: Bytes` — 이미지 바이너리.
|
|
101
|
-
- `opts.ext: string` — 확장자(`"png"`, `"jpg"` 등). MIME 미해석 시 throw.
|
|
102
|
+
- `opts.ext: string` — 확장자(`"png"`, `"jpg"` 등). MIME 미해석 시 throw. media 파일명/타입 결정에 사용.
|
|
102
103
|
- `opts.from: { r: number; c: number; rOff?: number | string; cOff?: number | string }` — 시작 위치(0 기반 행/열, `rOff`/`cOff` 는 셀 내부 EMU 오프셋).
|
|
103
104
|
- `opts.to?: { r: number; c: number; rOff?: number | string; cOff?: number | string }` — 끝 위치. 생략 시 `from` 의 한 칸 우하단(`from.r+1, from.c+1`)에 배치되어 약 1셀 크기로 들어간다. 명시하면 두 셀 앵커 사이로 늘려 배치.
|
|
104
105
|
|
|
@@ -115,6 +116,6 @@ const rows = await ws.getDataTable({
|
|
|
115
116
|
|
|
116
117
|
## 주의사항
|
|
117
118
|
|
|
118
|
-
- 모든 셀/시트 I/O 메서드는 `async` — lazy XML 로드 때문. 반복 쓰기는 await 누적이
|
|
119
|
-
- `ExcelWorkbook` 은 반드시 `close()` 해야 한다. 닫힌 워크북의
|
|
119
|
+
- 거의 모든 셀/시트 I/O 메서드는 `async` — lazy XML 로드 때문. 반복 쓰기는 await 누적이 필요하다(`cell`/`row`/`col` 객체 획득만 동기).
|
|
120
|
+
- `ExcelWorkbook` 은 반드시 `close()` 해야 한다. 닫힌 워크북의 시트 조회·내보내기 메서드는 throw.
|
|
120
121
|
- `setRecords` 헤더는 레코드 키에서 자동 생성되므로 열 순서를 고정하려면 모든 레코드의 키 등장 순을 일정하게 유지하거나 `setDataMatrix` 를 사용.
|
|
@@ -26,7 +26,7 @@ read(
|
|
|
26
26
|
|
|
27
27
|
동작: 스키마 표시명 집합에 해당하는 헤더만 골라 데이터 테이블을 읽고, 각 행을 필드 키로 역매핑한 뒤 값 변환 → Zod `safeParse` 검증한다. 빈/누락 값은 스키마 기본값 규칙(아래)으로 채우고, 한 행의 모든 매핑 값이 비면 그 행은 건너뛴다. 데이터가 0건이거나 검증 실패면 시트명을 포함해 throw(부분 반영 없이 전체 중단). 워크북은 내부에서 열고 finally 로 닫는다.
|
|
28
28
|
|
|
29
|
-
값 변환
|
|
29
|
+
값 변환 규칙(빈/누락이 아닌 값에 적용, optional/nullable/default 는 내부 타입으로 unwrap 후 판정):
|
|
30
30
|
|
|
31
31
|
- `ZodString` → 문자열(비문자열은 `String()`).
|
|
32
32
|
- `ZodNumber` → `num.parseFloat`.
|
|
@@ -48,7 +48,7 @@ write(
|
|
|
48
48
|
- `records: Partial<Schema>[]` — 출력할 레코드 배열(부분 객체 허용 — 누락 키는 빈 셀).
|
|
49
49
|
- `options.excludes?: (keyof Schema)[]` — 출력에서 제외할 필드 키 배열.
|
|
50
50
|
|
|
51
|
-
동작: 새 워크북에 시트 1개를 만들고, 0행에 표시명 헤더, 1행부터 각 레코드 값을 스키마 키 순서대로 쓴다. 전체 표에 4변 테두리, 필수(non-optional·non-nullable·non-default)이며 boolean 이 아닌 필드의 헤더 셀에 노란 배경(`"00FFFF00"`) 강조, zoom 85%, 0행
|
|
51
|
+
동작: 새 워크북에 시트 1개를 만들고, 0행에 표시명 헤더, 1행부터 각 레코드 값을 스키마 키 순서대로 쓴다. 전체 표에 4변 테두리, 필수(non-optional·non-nullable·non-default)이며 boolean 이 아닌 필드의 헤더 셀에 노란 배경(`"00FFFF00"`) 강조, zoom 85%, 0행 틀고정, 표 전체 범위(헤더행~마지막 데이터행)에 헤더 자동 필터(드롭다운)를 적용한다. **반환된 워크북의 close 는 호출자 책임** — 사용 후 반드시 `close()`(write 내부에서 실패 시에는 직접 close 후 rethrow).
|
|
52
52
|
|
|
53
53
|
## 사용 예
|
|
54
54
|
|
|
@@ -45,7 +45,7 @@ export const adminAppStructureItems: AppStructureItem[] = [
|
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
- `code` 는 부모부터 dot 으로 이어져 화면을 식별함 (위 예: `inventory.goods-inventory`). 라우팅 경로·권한 키가 모두 이 코드 기준.
|
|
48
|
-
- 그룹은 `children`
|
|
48
|
+
- 그룹은 `children` 을 가지며, 화면 전용 필드(`perms`·`url`·`subPerms`·`isNotMenu`)는 두지 않음. 표시 가능한 자식이 하나도 없으면 그룹도 메뉴에서 자동으로 빠짐.
|
|
49
49
|
- 외부 링크 화면은 `url` 지정.
|
|
50
50
|
|
|
51
51
|
| 필드 | 위치 | 용도 |
|
|
@@ -56,6 +56,8 @@ export const adminAppStructureItems: AppStructureItem[] = [
|
|
|
56
56
|
| `children` | 그룹 | 하위 항목 배열 |
|
|
57
57
|
| `url` | 화면 | 외부 링크 등 이동 경로 |
|
|
58
58
|
|
|
59
|
+
**새 화면 등록 관례**: 기존 화면 1개의 등록 위치·방식을 그대로 본떠 추가. `title` 은 화면명을 그대로, `code` 는 화면명을 dash-case 영문으로 음역한 슬러그(프로젝트의 기존 슬러그 규칙이 일관되면 그 규칙 우선).
|
|
60
|
+
|
|
59
61
|
## 3. 메뉴에 안 띄우고 화면만 두기
|
|
60
62
|
|
|
61
63
|
라우팅·내부 이동용이라 사이드 메뉴에는 노출하고 싶지 않은 화면은 `isNotMenu: true`.
|
|
@@ -113,7 +115,7 @@ this._sdAppStructure.permRecord.set(this.authInfo()!.user.permissionRecord);
|
|
|
113
115
|
|
|
114
116
|
**화면 안에서 권한 체크** — 화면 컴포넌트에서 `injectPermsSignal(<path>, <actions>)` 로 정의된 권한을 읽어 체크함. 첫 인자(권한 path)는 이 구조의 화면 fullCode(들). 체크 작성 관례(단순 체크는 인라인, `computed` 사용 기준)는 [client-component.md](./client-component.md) 의 '권한' 참조.
|
|
115
117
|
|
|
116
|
-
- `perms` 를 정의하지 않은 화면은 제약이
|
|
118
|
+
- `perms` 를 정의하지 않은 화면은 제약이 없으므로, `permRecord` 가 연결된 뒤에는 모든 권한이 활성으로 나옴(`permRecord` 미설정 상태인 로그인 전에는 빈 권한).
|
|
117
119
|
|
|
118
120
|
## 5. 기능 모듈로 메뉴 on/off
|
|
119
121
|
|
|
@@ -17,6 +17,20 @@
|
|
|
17
17
|
- 모든 파일명은 dash-case.
|
|
18
18
|
- 라이브러리(`@simplysm/angular`) 의 파일은 `sd-` prefix 적용 (`sd-button.ts`, `sd-crud-list.ts`).
|
|
19
19
|
|
|
20
|
+
**화면 정의 → 파일 구성**: 화면 정의(와이어프레임·동작) 의 화면 유형을 다음 역할 파일로 매핑.
|
|
21
|
+
|
|
22
|
+
| 화면 유형 패턴 | 파일 역할 |
|
|
23
|
+
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
24
|
+
| 마스터(체크박스·`[E N]`·5버튼바) / 시트 단일 | `<domain>.list.ts` |
|
|
25
|
+
| 단건 입력 폼 | `<domain>.detail.ts` |
|
|
26
|
+
| 좌 목록 + 우 단건 | `<domain>.view.ts` + `.list.ts` + `.detail.ts` |
|
|
27
|
+
| 좌 헤더 목록 + 우(헤더 정보 + 라인 시트) 마스터-라인 | `<domain>.view.ts` + `.list.ts` + `.detail.ts` — 우 라인 영역은 `.detail.ts` (헤더 단건 + 라인) |
|
|
28
|
+
| 모달 전용 비-CRUD 화면 (도구·검색·설정 등) | `<domain>.modal.ts` |
|
|
29
|
+
| 프린트 양식 | `<domain>.print-template.ts` |
|
|
30
|
+
|
|
31
|
+
- `<domain>` 은 화면명을 dash-case 영문으로 음역한 슬러그. 같은 역할 파일이 2개 이상이면 아래 "변형 파일" 규칙 적용.
|
|
32
|
+
- 동작 정의의 `→ [화면.X] 을 모달로 띄움` 표기는 표시 방식일 뿐 파일 역할이 아님. 화면.X 가 단건 편집이면 `.detail.ts` 를 모달로 띄우고(= "단건 입력 폼" 행), 모달 전용 비-CRUD UI 일 때만 `.modal.ts`. 판별 기준은 아래 "detail 과 modal 구분" 참조.
|
|
33
|
+
|
|
20
34
|
**위치**: 도메인이 있는 파일은 도메인 폴더 안에 둠. 도메인이 없는(범용) 파일은 `src/<역할>s/` 하위에 둠. 예: `src/controls/`, `src/modals/`.
|
|
21
35
|
|
|
22
36
|
**변형 파일**: 한 도메인 폴더 안에 같은 역할 파일이 2개 이상이면 `<domain>-<갈래>.<역할>.ts` 형식으로 갈래를 표시. 예 (`outbound-instruction/` 폴더):
|
|
@@ -71,6 +85,10 @@ Angular 기본과 다른 부분만 명시:
|
|
|
71
85
|
- 첫 줄에 `/* language=SCSS */` 주석 배치 (IDE 가 SCSS 로 인식하게 함).
|
|
72
86
|
- 내부 전용 클래스명은 `_` prefix (예: `._content`, `._button`).
|
|
73
87
|
|
|
88
|
+
## 시각 요소 배치 기준
|
|
89
|
+
|
|
90
|
+
화면 정의의 와이어프레임이 모든 시각 요소(버튼·필터·시트·탭·검색) 의 **존재·영역·순서** 결정의 1순위. 표준 슬롯이나 기본 UI 와 충돌하면 와이어프레임에 맞춰 슬롯을 비우거나 컴포넌트를 교체. 줄 수·픽셀 좌표는 기준이 아님 (폼 inline 자동 wrap 등의 표현 한계 때문).
|
|
91
|
+
|
|
74
92
|
## 화면 합성 패턴
|
|
75
93
|
|
|
76
94
|
화면은 list / detail / view 단위로 책임을 분리해 합성함.
|
|
@@ -116,7 +134,7 @@ view 의 합성 패턴 (예: `outbound-instruction.view.ts`):
|
|
|
116
134
|
- view 는 list 컴포넌트를 템플릿 변수(`#headerSheet`) 로 잡아 `selectedKeys()` 를 읽고 `doRefresh()` 를 호출.
|
|
117
135
|
- detail 의 단건 변경·삭제는 list 가 표시하는 동일 데이터에 반영해야 하므로, detail 의 `submitted` → list 의 `doRefresh()` 호출로 동기화.
|
|
118
136
|
- view 는 `sd-base-container` 를 루트로 두고, 내부 콘텐츠는 `#contentTpl` 슬롯에 배치.
|
|
119
|
-
- 미선택 빈
|
|
137
|
+
- 미선택 빈 상태는 위 예시의 구조(아이콘 + 안내 문구 `div`)를 그대로 사용하되, 안내 문구는 무엇을 선택하는지 드러내는 맥락 문구로 작성(예: `역할을 선택하세요.`). `tablerArrowLeft` 아이콘을 쓰므로 화면 컴포넌트에 `NgIcon` 등록 필요 ([아이콘](#아이콘) 참조).
|
|
120
138
|
|
|
121
139
|
### list + list 합성 (마스터-라인)
|
|
122
140
|
|
|
@@ -196,27 +214,7 @@ view 의 합성 패턴 (예: `outbound-instruction.view.ts`):
|
|
|
196
214
|
|
|
197
215
|
#### 편집형 detail 임베드 시 — 미저장 변경 가드
|
|
198
216
|
|
|
199
|
-
임베드한 detail 이 편집 가능(미저장 변경 상태를 가짐)하면, 페이지 이탈뿐 아니라 **마스터 전환**도 막아야 함. 마스터 전환은 라우터가 아니라 `sd-shared-data-select-list` 를 통해 일어나므로, 두 가드를 모두 배선할 수 있는 **view 로 가드를 끌어올림**.
|
|
200
|
-
|
|
201
|
-
```ts
|
|
202
|
-
detail = viewChild(RolePermissionDetail);
|
|
203
|
-
|
|
204
|
-
// 미저장 변경 보호: 페이지 이탈·마스터 전환 전에 자식 detail 의 변경 가드 확인
|
|
205
|
-
protected readonly checkCanLeave = (): boolean => {
|
|
206
|
-
const detail = this.detail();
|
|
207
|
-
return detail == null || detail.checkIgnoreChanges();
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
constructor() {
|
|
211
|
-
setupCanDeactivate(this.checkCanLeave); // 페이지 이탈 가드
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
```html
|
|
216
|
-
<sd-shared-data-select-list ... [canChangeFn]="checkCanLeave">
|
|
217
|
-
...
|
|
218
|
-
</sd-shared-data-select-list>
|
|
219
|
-
```
|
|
217
|
+
임베드한 detail 이 편집 가능(미저장 변경 상태를 가짐)하면, 페이지 이탈뿐 아니라 **마스터 전환**도 막아야 함. 마스터 전환은 라우터가 아니라 `sd-shared-data-select-list` 를 통해 일어나므로, 두 가드를 모두 배선할 수 있는 **view 로 가드를 끌어올림**. 가드 배선 코드(`viewChild`·`checkCanLeave`·`setupCanDeactivate`·`[canChangeFn]`)는 [client-shared-data.md](./client-shared-data.md) 의 '좌측 선택 목록 + 우측 상세(master-detail) 레이아웃' 섹션 참조.
|
|
220
218
|
|
|
221
219
|
배선 약속:
|
|
222
220
|
|
|
@@ -260,7 +258,7 @@ perms = injectPermsSignal(
|
|
|
260
258
|
);
|
|
261
259
|
```
|
|
262
260
|
|
|
263
|
-
- 첫 인자: **권한 path 목록** (도메인 트리 좌표).
|
|
261
|
+
- 첫 인자: **권한 path 목록** — app-structure 의 화면 `fullCode`(들) (점으로 결합된 도메인 트리 좌표).
|
|
264
262
|
- 둘째 인자: **확인할 action 목록**. `perms()` 의 반환값은 사용자가 보유한 action 의 string 배열.
|
|
265
263
|
|
|
266
264
|
**사용 약속**:
|
|
@@ -351,6 +349,7 @@ if (!result) return;
|
|
|
351
349
|
- **`title`** — 모달 헤더 제목.
|
|
352
350
|
- **`inputs`** — 모달 컴포넌트가 받을 input 시그널 값. 없으면 `{}`.
|
|
353
351
|
- **반환값** — 모달 컴포넌트가 close 시 emit 한 페이로드. 사용자가 닫기(X)·취소로 닫으면 `undefined`.
|
|
352
|
+
- **close 규약** — 모달 컴포넌트는 `SdModalContentDef` 의 `close` output 만 사용. 임의 close output 규약을 따로 만들지 말 것 — 호출 측은 위 반환값(페이로드) 으로만 결과를 받음.
|
|
354
353
|
|
|
355
354
|
## `mark` 헬퍼
|
|
356
355
|
|
|
@@ -367,7 +366,7 @@ doRefresh(): void {
|
|
|
367
366
|
**2. 객체·배열 시그널 내부 변경 알림** — 시그널이 들고 있는 객체의 _필드만_ 변경된 경우 시그널 자체는 변경 알림을 보내지 않음. 양방향 바인딩 자식의 변경 이벤트에 묶어 호출.
|
|
368
367
|
|
|
369
368
|
```ts
|
|
370
|
-
filter = signal<IFilter>({
|
|
369
|
+
filter = signal<IFilter>({ ... });
|
|
371
370
|
```
|
|
372
371
|
|
|
373
372
|
```html
|
|
@@ -622,6 +621,7 @@ async onSubmit(): Promise<void> {
|
|
|
622
621
|
|
|
623
622
|
- `[width]` 는 **미명시가 기본** (자동). px 지정은 사용자가 명시 지시한 경우에만 적용.
|
|
624
623
|
- 영역 폭(`flex-min` 의 `style="width: ..."` 등) 도 동일.
|
|
624
|
+
- 명시 지시로 px 폭을 지정할 땐 그 의도·근거를 바로 위 코드 주석으로 남김 — 주석 없는 px 폭은 리뷰에서 비-합의 지정으로 간주됨.
|
|
625
625
|
|
|
626
626
|
**셀 본문 약속**:
|
|
627
627
|
|